如何评价1:(2:(3:[]))?
在我们到达[1,2,3]之前会采取什么改写步骤?
是吗
1:(2:([3])
1:([2,3])
[1,2,3]
还是其他什么?上述方式是唯一的方法吗?或者还有其他方式吗?
答案 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