对于monad,可以通过bind来定义join吗?
在Haskell中,monads是根据函数return和bind定义的,其中return的类型a -> ma
,bind的类型为ma -> (a -> mb) -> mb
。 之前已经指出单子也可以用返回和连接来定义,其中连接是类型为m (ma) -> ma
的函数。 绑定可以根据连接来定义,但是可能相反吗? 可以根据绑定来定义连接吗?
如果没有加入,我不知道如果我以某种方式获得了“两次包裹”一元值, m (ma)
- 没有任何函子或monad操作“删除任何图层”,我会做什么。 如果这是不可能的,为什么Haskell和其他monad实现在绑定方面定义它们? 它似乎严格地比基于连接的定义更有用。
有可能的:
join :: Monad m => m (m a) -> m a
join m = (m >>= id)
注意>>=
的棘手实例:
(>>=) :: m b -> (b -> m c) -> m c
-- choosing b ~ m a , c ~ a
(>>=) :: m (m a) -> (m a -> m a) -> m a
所以我们可以正确选择id
作为第二个参数。
是的,这很简单:
join m = m >>= id
绑定( >>=
)确实“删除图层”:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
直觉告诉我“得到了一些a
出去了的的ma
”,并于随后把a -> mb
功能,然后产生一个mb
的结果。
人们通常会说它需要函数参数才能以m
重新计算输出,但事实并非如此。 它要求函数的输出是以m
为单位的东西,但是包装的来源并不重要。
在实现join
的情况下,我们从“双重包装”开始: m (ma)
。 我们可以将它插入bind的签名,并立即找出绑定“双重包装”值时可以使用的函数的类型:
m (m a) -> (m a -> m b) -> m b
现在,用于绑定的函数将接收一个已经包含在m
。 所以我们不必“重新包装”任何东西; 如果我们未经修改就返回它,它已经是输出的正确类型。 有效地,这是“删除了一层包装” - 这适用于任何层,但最后一层。
所以这告诉我们我们只需要绑定id
:
join = (>>= id)
链接地址: http://www.djcxy.com/p/33223.html