我一直在阅读UPenn的CS194,目前正在Monads的第7讲。我认为我在Monads上得到了一个好的处理,直到我看到序列函数的实现并开始探索。
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (ma:mas) = do
a <- ma
as <- sequence mas
return (a:as)
乍一看这似乎很直观,但是当我深入研究它时,我遇到了许多问题:
return []
的类型为:return [] :: Monad m => m [t]
。在同一课程的前面,Monad
的{{1}}实例将返回定义为:[]
。这是如何导致return x = [x]
的类型签名m [t]
?
return []
。什么是a <- ma
的类型,假设我用a
调用了序列?根据{{1}}的{{1}}实例定义:
[Just 5, Just 9]
我认为Monad
或Maybe
在Just x >>= k = k x
的情况下是x
。但它必须是a
的{{1}}。当sequence
的实例定义中的Num
似乎将Monad
拉出Num
时,x
如何成为Num
的monad?
答案 0 :(得分:3)
return []
的类型是Monad m => m [t]
- 这里,[]
是[t]
的一个实例,即一些任意类型的列表(类型是任意的,因为它& #39;是空列表,因此无论如何都没有该类型的实例)。如果您替换列表monad,return
的类型为t -> [t]
,return []
会产生[[]]
。令人困惑的是,monad和包含的值都是列表。
return
的类型一般为Monad m => t -> m t
。如果您专注于列表,则会获得t -> [t]
,因此列表类型取代m
。列表的特殊语法使这更加混乱;如果您使用may monad,专门的返回类型为t -> Maybe t
,因此您可以清楚地看到m
如何被Maybe
取代。在monad中,return []
的类型是Maybe [t]
:monad现在包含了一些列表。
return []
的类型是Monad m => m [t]
,由monad包装的列表。如果您使用列表monad,则将m
替换为列表构造函数,并获取[[t]]
,这是正确的类型。
关于第二个问题,为什么你认为a
必须是monad?
在评论澄清后编辑
在您给出的示例调用sequence [Just 5, Just 9]
中,monad可能不是列表;该列表是sequence
类型所需的普通列表。请记住,它需要[m a]
作为输入。当您提供Num a => [Maybe a]
作为输入时,会生成monad Maybe
,结果类型为Num a => Maybe [a]
。 sequence
将可选值列表转换为可选列表。这意味着,在sequence
的第一种情况下,return []
适用于Maybe
&#39; return
,意味着Just []
。这是有道理的,因为在monad中调用sequence []
应该返回Just []
。
现在,在第二种情况的do-block中,我们有一堆变量,它有助于找出每种变量的类型。我会针对数字Maybe
和Int
的具体情况这样做;获取通用类型归结为在所有这些情况下简单地将Maybe
替换为m
,将Int
替换为a
,并添加约束。
整个输入的类型为[Maybe Int]
。第二个案例模式 - 将其与(ma:mas)
匹配,从列表中选择第一个元素。因此ma
具有列表元素的类型Maybe Int
,而mas
是列表的其余部分,因此类型为[Maybe Int]
。
在do-block中,ma
用箭头符号打开,结果为a
,其类型为ma
,其中monad被剥离,即{{} 1}}。
然后,Int
递归调用输入的其余部分sequence
,其类型为mas
。替换为[Maybe Int]
的类型表明结果类型为sequence
。此值再次展开,因此目标Maybe [Int]
的类型为as
。
在最后一行中,[Int]
(类型a
)前置于Int
(类型as
),产生更长的列表([Int]
)。结果将发送给[Int]
,return
将其包含在Just
(Maybe [Int]
)中,以匹配sequence
的结果类型。
顺便说一下,如果你想通过do-blocks详细跟踪类型,你首先应该将它们与lambdas一起用于正常的组合。