关于Haskell序列函数的问题

时间:2016-01-20 14:45:42

标签: haskell monads

我一直在阅读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)

乍一看这似乎很直观,但是当我深入研究它时,我遇到了许多问题:

  1. return []的类型为:return [] :: Monad m => m [t]。在同一课程的前面,Monad的{​​{1}}实例将返回定义为:[]。这是如何导致return x = [x]的类型签名m [t]

  2. return []。什么是a <- ma的类型,假设我用a调用了序列?根据{{​​1}}的{​​{1}}实例定义:

    [Just 5, Just 9]

    我认为MonadMaybeJust x >>= k = k x 的情况下是x。但它必须是a的{​​{1}}。当sequence的实例定义中的Num似乎将Monad拉出Num时,x如何成为Num的monad?

1 个答案:

答案 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中,我们有一堆变量,它有助于找出每种变量的类型。我会针对数字MaybeInt的具体情况这样做;获取通用类型归结为在所有这些情况下简单地将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将其包含在JustMaybe [Int])中,以匹配sequence的结果类型。

顺便说一下,如果你想通过do-blocks详细跟踪类型,你首先应该将它们与lambdas一起用于正常的组合。