用`[[​​a]]`Monad理解`sequence`

时间:2015-03-06 16:33:48

标签: haskell

假设:

Prelude>[ [Just 10, Just 20], [Just 5] ]
[ [Just 10, Just 20], [Just 5] ]

它有类型:

Prelude> :t [ [Just 10, Just 20], [Just 5] ]
[ [Just 10, Just 20], [Just 5] ] :: Num a => [[Maybe a]]

我想将其应用于sequence

Prelude> :t sequence
sequence :: Monad m => [m a] -> m [a]

上面列表中的Monad m是:[a],据我所知,所以我希望这些类型排成一行:

sequence :: Monad m => [m a] -> m [a]
                       [[a]] -> [[a]]

假设没错,那么请帮助我理解输出:

Prelude> sequence [ [Just 10, Just 20], [Just 5] ]
[[Just 10,Just 5],[Just 20,Just 5]]

2 个答案:

答案 0 :(得分:3)

sequence做的是转变

[foo, bar, baz]

类似

do
  x <- foo
  y <- bar
  z <- baz
  return [x, y, z]

在你的情况下,我们有

do
  x <- [Just 10, Just 5]
  y <- [Just 5]
  return [x, y]

相同
foreach x in [Just 10, Just 5]
  foreach y in [Just 5]
    return [x, y]

in psuedo-OO syntax。

现在应该很明显为什么你会得到你的结果。

答案 1 :(得分:3)

仅使用Int而不是Maybe Int来执行此操作可能更容易:

> sequence [[10, 20], [5]]
[[10,5],[20,5]]
it :: [[Int]]

您推断出的类型签名是正确的,在这种情况下它的类型为[[a]] -> [[a]],在我的示例中为a ~ Int,在示例中为a ~ Maybe Int。每当在列表monad中使用sequence时,我都会将其视为N维笛卡尔积。它不喜欢像

这样的东西
sequence [a, b, c] = do
    x <- a
    y <- b
    z <- c
    return [x, y, z]

但是使用任意数量的元素,而不仅仅是3.其他一些例子可能有助于解释:

sequence [["a1", "a2", "a3"], ["b1", "b2"], ["c1", "c2", "c3"]]
[
  ["a1","b1","c1"],["a1","b1","c2"],["a1","b1","c3"],["a1","b2","c1"],["a1","b2","c2"],["a1","b2","c3"],
  ["a2","b1","c1"],["a2","b1","c2"],["a2","b1","c3"],["a2","b2","c1"],["a2","b2","c2"],["a2","b2","c3"],
  ["a3","b1","c1"],["a3","b1","c2"],["a3","b1","c3"],["a3","b2","c1"],["a3","b2","c2"],["a3","b2","c3"]
]

如果你仔细研究这个输出,你会发现a的每个元素与b的每个元素以及c中的每个元素相匹配。由于有3 a s,2 b和3 c s,因此输出中有3*2*3 == 18个元素。