GHCi 中的严格列表评估
Strict list evaluation in GHCi
考虑程序:
l = [0..10]
l' = map (+1) [0..10]
运行 使用 GHCi,输入 :sprint l
和 :sprint l'
将显示两个列表都未计算。但是,在 运行 length l
和 length l'
之后,然后再次使用 sprint
:
l = [0,1,2,3,4,5,6,7,8,9,10]
和
l' = [_,_,_,_,_,_,_,_,_,_,_]
我做了类似的实验,并尝试使用 let
将变量绑定到 GHCi 中的列表,但是只有在 l
的情况下(在程序顶层定义如上)是列表总是完全评估。
这些行为都指向优化功能,但是我想知道是否有更详细的答案(策略)'under-the-hood'。
原始 [0..10]
列表的元素在两种情况下都进行了评估。 l'
案例中未计算的是将 (+1)
应用于列表元素的结果。相反,如果我们 map the function strictly:
会发生什么
GHCi> import Control.Monad
GHCi> l'' = (+1) <$!> [0 :: Integer ..10]
GHCi> :sprint l''
l'' = _
GHCi> length l''
11
GHCi> :sprint l''
l'' = [1,2,3,4,5,6,7,8,9,10,11]
(请注意,我专门研究整数文字,因此 GHCi 提示中没有单态限制不会导致与从文件加载代码时得到的结果不同。)
值得注意的是 enumFromTo
for Integer
(使用范围归结为),as implemented by base, evaluates the elements in order to know when to stop generating them. That's to say it is not length
that forces the list elements, as we'd hope from looking at its definition:
length :: [a] -> Int
length xs = lenAcc xs 0
lenAcc :: [a] -> Int -> Int
lenAcc [] n = n
lenAcc (_:ys) n = lenAcc ys (n+1)
为了更好地了解 length
在这里的表现,我们可能会尝试使用 replicate
生成的列表重复您的实验(与 length
一样,它不会查看元素)未完全评估的值:
GHCi> n = 2 * (7 :: Integer) -- let-bindings are lazy.
GHCi> :sprint n
n = _
GHCi> l''' = replicate 3 n
GHCi> :sprint l'''
l''' = _
GHCi> length l'''
3
GHCi> :sprint l'''
l''' = [_,_,_]
考虑程序:
l = [0..10]
l' = map (+1) [0..10]
运行 使用 GHCi,输入 :sprint l
和 :sprint l'
将显示两个列表都未计算。但是,在 运行 length l
和 length l'
之后,然后再次使用 sprint
:
l = [0,1,2,3,4,5,6,7,8,9,10]
和
l' = [_,_,_,_,_,_,_,_,_,_,_]
我做了类似的实验,并尝试使用 let
将变量绑定到 GHCi 中的列表,但是只有在 l
的情况下(在程序顶层定义如上)是列表总是完全评估。
这些行为都指向优化功能,但是我想知道是否有更详细的答案(策略)'under-the-hood'。
原始 [0..10]
列表的元素在两种情况下都进行了评估。 l'
案例中未计算的是将 (+1)
应用于列表元素的结果。相反,如果我们 map the function strictly:
GHCi> import Control.Monad
GHCi> l'' = (+1) <$!> [0 :: Integer ..10]
GHCi> :sprint l''
l'' = _
GHCi> length l''
11
GHCi> :sprint l''
l'' = [1,2,3,4,5,6,7,8,9,10,11]
(请注意,我专门研究整数文字,因此 GHCi 提示中没有单态限制不会导致与从文件加载代码时得到的结果不同。)
值得注意的是 enumFromTo
for Integer
(使用范围归结为),as implemented by base, evaluates the elements in order to know when to stop generating them. That's to say it is not length
that forces the list elements, as we'd hope from looking at its definition:
length :: [a] -> Int
length xs = lenAcc xs 0
lenAcc :: [a] -> Int -> Int
lenAcc [] n = n
lenAcc (_:ys) n = lenAcc ys (n+1)
为了更好地了解 length
在这里的表现,我们可能会尝试使用 replicate
生成的列表重复您的实验(与 length
一样,它不会查看元素)未完全评估的值:
GHCi> n = 2 * (7 :: Integer) -- let-bindings are lazy.
GHCi> :sprint n
n = _
GHCi> l''' = replicate 3 n
GHCi> :sprint l'''
l''' = _
GHCi> length l'''
3
GHCi> :sprint l'''
l''' = [_,_,_]