haskell - GHCi 中的严格列表评估
问题描述
考虑程序:
l = [0..10]
l' = map (+1) [0..10]
使用 GHCi 运行它,然后输入:sprint l
and:sprint l'
将显示两个列表都未评估。但是,在运行length l
然后length l'
再次使用之后sprint
:
l = [0,1,2,3,4,5,6,7,8,9,10]
和
l' = [_,_,_,_,_,_,_,_,_,_,_]
我已经进行了类似的实验并尝试将变量绑定到 GHCi 中的列表let
,但是只有在l
(如上在程序顶层中定义)的情况下,列表总是被完全评估。
这些行为都指向优化功能,但是我想知道是否有更详尽的答案(策略)“幕后”。
解决方案
在这两种情况下都对原始[0..10]
列表的元素进行了评估。在此l'
案例中未评估的是应用于(+1)
列表元素的结果。相反,如果我们严格映射函数,会发生以下情况:
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
(使用范围归结为),由base实现,评估元素以便知道何时停止生成它们。也就是说,它并不是length
强制列表元素,正如我们希望通过查看它的定义:
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''' = [_,_,_]
推荐阅读
- python - TF 2.0 中具有多个附加输入的自定义损失函数
- asp.net - 什么可以用来替代旧版 .NET Web 应用程序中的 Windows 身份验证?
- android - 合并回收站查看项目
- excel - 无法使用 Excel 中的“文本到列”和“单元格格式”选项将带有美元符号和逗号的美元金额格式化为简单数字
- javascript - 如何使用 css 显示网格使我的列号动态化?
- javascript - Chart JS - 页面刷新后记住隐藏标签状态
- java - Firebase:每次都必须验证用户,它运行应用程序
- flutter - Flutter 应用错误 发生异常。_TypeError(类型'String'不是'index'类型'int'的子类型)
- c++ - 为什么这个类模板参数被视为转发引用?
- java - 如何从 Java 消费者的主题中的消息中从模式注册表中检索 AVRO 模式