现在当你看它的时候,f(a -> b)
可以写成(a -> b)
不,不能。此时你的直觉(危险地)还很遥远。这就像说锤子非常适合拧入螺丝,因为它已经可以用来钉钉子*。你不能简单地放弃f
在这里,它是类型**的一部分。
相反,让我们弄清楚事实。一个Applicative
有三个相关的函数,计数Functor
's fmap
:
fmap :: Functor f => (a -> b) -> f a -> f b
pure :: Applicative f => a -> f a
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
这是另一个事实:您可以定义绑定 ((>>=)
) 按照join
反之亦然:
join :: Monad m => m (m a) -> m a
join k = k >>= id
(>>=) :: Monad m => m a -> (a -> m b) -> m b
k >>= f = join (fmap f k)
您在此处提供的 join 和 bind 的实现是 Monad 定义的一部分,还是仅 join 和 bind 签名是 Monad 定义的一部分? [...] 所以现在我问自己他们为什么要打扰。
当然,这些不是官方定义,因为它们永远不会终止。你必须定义(>>=)
对于你的类型,如果你想让它成为一个单子:
instance Monad YourType where
k >>= f = ...
另外,您的连接定义使用的 id 不在 Monad 接口中,为什么它在数学上是合法的?
首先,id :: a -> a
是为任何类型定义的。其次,单子的数学定义实际上是通过join
。所以它“更”***合法。但最重要的是,我们可以根据以下方面来定义单子定律:join
(锻炼)。
如果我们创建了join
via Applicative
,我们还可以创建绑定。如果我们无法创造join
via Applicative
方法,我们也无法得出bind
. And join
的类型实际上很明显我们不能从中导出它Applicative
:
join :: Monad m => m (m a) -> m a
-- ^ ^ ^
Join 可以删除其中之一m
层。让我们检查一下是否可以在其他方法中执行相同的操作:
fmap :: Functor f => (a -> b) -> f a -> f b
^ ^
0 here 1 here
pure :: Applicative f => a -> f a
^ | ^
0 here | 1 here
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
^ ^
1 here 1 here
答案是否定的:我们没有提供任何工具Applicative
使我们能够崩溃多个m
变成了一个。这也是写在类型分类百科全书 https://wiki.haskell.org/Typeclassopedia#Monad就在另一个问题中引用的段落之后:
为了从不同的角度了解 Monad 增强的功能,让我们看看如果我们尝试实现会发生什么(>>=)
按照fmap
, pure
, and (<*>)
。我们被赋予了一个值x
类型的m a
,和一个函数k
类型的a -> m b
,所以我们唯一能做的就是申请k
to x
。当然,我们不能直接应用它;我们必须使用fmap
将其举过m
。但它的类型是什么fmap k
?嗯,这是m a -> m (m b)
。所以当我们将其应用到x
,我们留下了一些类型m (m b)
——但现在我们陷入困境;我们真正想要的是m b
,但是没有办法从这里到达那里。我们可以添加m
正在使用pure
,但是我们没有办法折叠多个m
合而为一。
注意join
无法摆脱m
完全地,这将是一个完全的提取,并且——取决于一些其他功能——一个特征comonad https://stackoverflow.com/q/34837150/1139697。不管怎样,请确保你的直觉不会误入歧途。信任并使用类型。
* That comparison is a little bit bad, because you could actually try to dive a screw in with a hammer into a piece of wood. So think of a plastic screw, a rubber hammer and a carbon steel plate you want to drive the nail in. Good luck.
** Well, you can drop it, but then the type changes drastically.
*** Given that (>>=)
and join
are equivalent of power and any (>>=)
using formula can be transformed to one only using join
, they are of course both mathematical sound.