【发布时间】:2022-07-08 03:14:50
【问题描述】:
tl;博士
20 < length $ take 10 $ whatever 需要whatever 才能成功地对列表(至少是[] 或(_:_))进行模式修补,这难道不是“缺乏”懒惰吗?
或者,换句话说,为什么不是(20 >) . length . take 10 === const True,所以将它们中的任何一个应用于任何东西都不需要对参数进行任何评估?
(20 >) . length . take 10 !== const True 是必需品吗?还是设计选择?无论哪种情况,为什么?
前言
这是对my previous question的跟进。
在那里我问为什么@987654322@ error 会反复无限地打印*** Exception: 。
答案令人满意。
我的运气
但是,我玩了一下ghci,发现take 0 $ fix error 预期会返回"",而length $ take 0 $ fix error 会返回0。
另一方面,以下打印*** Exception: 无限流:
20 > (length $ take 10 $ fix error)
我了解 如果 甚至计算了 fix error 的一个元素(实际上是尝试),结果就是这样,但我的问题是:为什么首先需要对它们中的任何一个进行评估,在那个特定的表达式中?毕竟,length $ take 10 $ whatever 不能是 <= 10,因此是 < 20,所以表达式的计算结果应该是 True。
实际上,我看到20 > (length $ take 10 $ [fix error]) 立即返回True。可能整点是take 10 期望在[a] 上工作,所以length $ take 10 $ [fix error] 不需要评估fix error 以确保它在[a] 上工作。事实上,我也验证了 20 > (length $ take 10 $ undefined) 错误(即使没有无限重复错误),而 20 > (length $ take 10 $ [undefined]) 返回 True。
也许这就是Willem Van Onsem meant in this comment。
不管怎样,因为我可以把上面的表达式写成
((20 >) . length . take 10) $ fix error
我很想说
(20 >) . length . take 10 === const True
因此我会说((20 >) . length . take 10) $ fix error 返回True 是合理的,就像const True $ fix error 返回True。
但事实并非如此。为什么?
【问题讨论】:
-
您是在问为什么要观察自己在 Haskell 中所做的事情,还是在问如果我们从头开始设计一种新的类似 Haskell 的语言,原则上会存在什么行为?
-
@DanielWagner 后者。
-
好的。假设我们已经制定了一个对程序含义足够灵活的假设规范,允许编译器执行重写
length (take 10 x) < 20->True如果它可以发现它。为了使编译器能够发现和执行重写,您的实施计划是什么? -
目标是符号计算还是证明某些程序的属性?如果是这样,那么在某些范式中,声明
(20 >) . length . take 10 === const True是可证明的和机器可验证的(例如 Agda、Coq)。还是您希望编译器为您“修复”某些类型的程序?如果是这样,那么对您的问题的真正无聊的答案是:它以这种方式工作,因为该语言为程序分配了一致且可预测的操作语义,并且这种具有take 10 undefined = undefined的操作语义的选择还允许使用真实世界的广泛类程序使用。 -
... 然而,在今天的 Haskell 中,您可以使用名称
length和take定义不同的符号,这样length . take 10 $ [1,2, ...]计算为10和 @987654368 并不是不可想象的@ 计算为True。但是没有规范或通用的方法可以做到这一点。 如何定义这些符号完全取决于你想要完成什么。
标签: haskell functional-programming pattern-matching lazy-evaluation