简单列表创建中的评估顺序是什么?

时间:2014-07-20 18:05:36

标签: haskell

如何评价1:(2:(3:[]))?

在我们到达[1,2,3]之前会采取什么改写步骤?

是吗

   1:(2:([3])
   1:([2,3])
   [1,2,3]

还是其他什么?上述方式是唯一的方法吗?或者还有其他方式吗?

1 个答案:

答案 0 :(得分:13)

Haskell在这里没有任何实际评估的东西,因为:是列表的构造函数。当您编写[1, 2, 3]之类的内容时,编译器首先将其解析为1 : 2 : 3 : []形式,而这是它在内存中的表示。这就像询问Just 1的评估顺序。没有评估订单,因为它已经处于“评估最多”的形式,也称为普通形式。

对于列表,普通表单是在空列表前面拼凑在一起的元素。如果有帮助,您可以考虑定义为

的列表
data [a] = [] | a : [a]

或者

data List a = Empty | Cons a (List a)

当您进行模式匹配时,如

f (x:xs) = ...

这相当于像

那样进行模式匹配
f (Cons x xs) = ...

唯一真正的区别是使用的名称。


所以我猜你的问题的答案是,你的评价是向后的,你不是从1:2:3:[][1, 2, 3],而是从[1, 2, 3]到{{1}虽然这一步骤发生在去糖过程中。至于列表推导,这些使用1:2:3:[]>>等monadic函数将其去糖化成地图和过滤器。当您看到>>=之类的内容时,实际上会将[1..10]实例用于其元素,并对Enum和类似函数进行去糖。所有这些函数都使用fromEnumTo:级别的列表,因此它们只是处理列表类型的构造函数,就像处理任何其他数据类型一样。


作为证明,如果我有代码

[]

我用module Foo where x :: [Int] x = [1, 2, 3] 编译了它,我得到了

ghc -c Foo.hs -ddump-ds

其中有很多额外的元数据,所以让我们删除所有额外的类型注释,模块名称和其他噪音:

Foo.x :: [GHC.Types.Int]
[LclIdX]
Foo.x =
  GHC.Types.:
    @ GHC.Types.Int
    (GHC.Types.I# 1)
    (GHC.Types.:
       @ GHC.Types.Int
       (GHC.Types.I# 2)
       (GHC.Types.:
          @ GHC.Types.Int (GHC.Types.I# 3) (GHC.Types.[] @ GHC.Types.Int)))

甚至更多删除

Foo.x :: [Int]
Foo.x = GHC.Types.: 1 (GHC.Types.: 2 (GHC.Types.: 3 []))

请注意,在核心(GHC编译Haskell源代码,使用的3种中间语言之一)中,我们不需要以前缀形式围绕运算符的parens。但是很容易看出,一旦所有东西都被脱糖,它就会被简单地表示为一起列出的列表。

但是等等!我想you said that the parens weren't needed?当它是中缀形式时也是如此,但现在x :: [Int] x = : 1 (: 2 (: 3 [])) 被用作前缀函数。很容易看出,使用前缀时,需要使用parens,尤其是当您将:替换为:Cons替换为[]时:

Empty

由于以下内容不会进行类型检查。这看起来像x = Cons 1 (Cons 2 (Cons 3 Empty)) 需要6个参数!

Cons