为什么seq不好?

Haskell有一个名为seq的神奇函数,它接受任何types的参数并将其减less为弱头范式 (WHNF)。

我已经读了几个消息来源(不是我现在能记得他们是谁……),声称“多态性seq是坏的”。 他们以什么方式“坏”?

类似地,还有rnf函数,它将参数减less到Normal Form (NF)。 但这是一个类方法; 它不适用于任意types。 对我来说,似乎是“显而易见的”,可以改变语言规范,将其作为内置原语提供,类似于seq 。 这大概会比只有seq更“糟糕”。 这是怎样的?

最后,有人build议给seqrnfpar和类似于id函数的types,而不是const函数,因为它现在是一个改进。 怎么会这样?

据我所知,一个多态seq函数是不好的,因为它削弱了自由定理,换句话说,没有seq有效等式在seq中不再有效。 例如,平等

 map g (f xs) = f (map g xs) 

对于所有函数g :: tau -> tau' ,所有函数列表xs :: [tau]和所有多态函数f :: [a] -> [a] 。 基本上,这个平等说明f只能重新排列其参数列表的元素,或者删除或重复元素,但不能创造新的元素。

说实话,它可以发明元素,因为它可以将非终止计算/运行时错误“插入”列表中,因为错误的types是多态的。 也就是说,这种平等已经在诸如Haskell之类的编程语言中没有seq 。 下面的函数定义为这个方程提供了一个反例。 基本上,在左边g “隐藏”错误。

 g _ = True f _ = [undefined] 

为了修正方程, g必须是严格的,也就是说,它必须将错误映射到错误。 在这种情况下,平等再次成立。

如果添加一个多态seq运算符,则等式再次中断,例如,以下实例化就是一个反例。

 g True = True f (x:y:_) = [seq xy] 

如果我们考虑列表xs = [False, True] ,那么我们有

 map g (f [False, True]) = map g [True] = [True] 

但另一方面

 f (map g [False, True]) = f [undefined, True] = [undefined] 

也就是说,您可以使用seq使列表中某个位置的元素依赖于列表中另一个元素的定义。 如果g是总数,那么等式再次成立。 如果你在自由定理中进行了讨论,请查看免费的定理生成器 ,它允许你指定你是在考虑一个有错误的语言,甚至是一个带有seq的语言。 虽然这似乎不太实际,但seq打破了一些用于改进function性程序性能的转换,例如,在seq存在下, foldr / build融合失败。 如果在seq存在的情况下对自由定理的更多细节进行了讨论,请看seq中存在的自由定理 。

据我所知,已经知道一个多态seq打破了一定的转换,当它被添加到语言。 但是,别名也有缺点。 如果你添加一个基于types的seq ,你可能需要在你的程序中添加大量的types约束,如果你在一个深层的地方添加一个seq 。 此外,没有select省略seq ,因为已经知道可以使用seq来修复空间泄漏。

最后,我可能会错过一些东西,但我不明白typesa -> aseq运算符是如何工作的。 seq的线索是,如果另一个expression式被评估为正常forms,它将评估一个expression式以标准forms。 如果seq已经键入a -> a那么就不能根据另一个expression式的评估来对一个expression式进行评估。

在这个答案中给出了另一个反例 – monad不能满足sequndefined单子法则。 而且由于undefined在图灵完全语言中是不可避免的,所以责备的是seq