12

我刚刚开始学习haskell(字面意思是今晚!)而且我在理解列表推导的逻辑时遇到了一些麻烦,更具体地说是<-运算符。Learn You Some Haskell上的一个小例子查找所有长度小于 10 的元组:

ghci> let triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]

我最初的理解是这些都会一起递增,但是在看到输出后,我真的不理解这些列表的递增方法。另一个让我印象深刻的例子是:

ghci> let rightTriangles = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]

我非常感谢您对这些内容进行一些解释,感谢您对我缺乏 Haskell 智能的耐心。

4

3 回答 3

20

[作“list of”、|“for”、<-“in”、,“and”。

枚举以嵌套方式完成。[ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]是真的

for c from 1 to 10 step 1:
   for b from 1 to c step 1:
      for a from 1 to b step 1:
          if (a^2 + b^2 == c^2):
             emit (a,b,c)

不过,在 Haskell 中,上述内容是通过以下翻译实现的

[1..10] >>= (\c->               -- (a function of 'c', producing ...
  [1..c]  >>= (\b->               -- (a function of 'b', producing ...
    [1..b]  >>= (\a->               -- (a function of 'a', producing ...
      if a^2+b^2==c^2 then [(a,b,c)] else []
      -- or: [(a,b,c) | a^2+b^2==c^2]
      )))

所以你真的可以在这里看到嵌套结构。(>>=)也没什么神秘的。读>>=作“fed into”或“pushed through”,虽然它的正式名称是“bind”。它被定义(对于列表)为

(xs >>= f) = concatMap f xs = concat (map f xs)

f这里按顺序map在 的每个元素上调用 (by ) 。xs它必须生成列表,以便它们可以与concat. 由于在(例如)[]上消除了空列表,因此从最终输出中消除了所有未通过测试的元素。concatconcat [[1], [], [3]] == [1,3]


有关完整翻译,请参阅Haskell 98 报告的第 3.11 节,列表理解。一般来说,列表推导可能包含一个模式,而不仅仅是一个变量名。理解力

[e | pat <- ls, ...]  

被翻译为

ls >>= (\x -> case x of pat -> [e | ...] ;
                        _   -> [] )

哪里pat是一些模式,并且x是一个新鲜的变量。当存在模式不匹配时,将生成一个空列表(而不是运行时错误),并且跳过该元素xls这对于附加的基于模式的过滤很有用,例如[x | Just x <- ls, even x],其中所有的Nothingsls都被悄悄地忽略了。

于 2013-05-29T03:59:21.533 回答
4

[ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]表示,对于 (a,b,c) 的所有组合,其中 a 在 [1..10] 中,b 在 [1..10] 中,c 在 [1..10] 中

如果您想要 (1,1,1) (2,2,2) 种类,您应该使用zip:zip [1..10] [1..10]或 3 个列表,zip3 [1..10] [1..10] [1..10]

于 2013-05-29T03:50:10.663 回答
1

我认为列表理解语法是 Haskell 尝试在语言中获取Set-builder 表示法。我们使用 '[' 而不是 '{' 和 '<-' 而不是 '∈'。列表理解语法甚至可以推广到任意 monad。

于 2013-06-07T07:17:22.930 回答