在Haskell中评估函数->()有什么规则?

Kry*_*oon 10 haskell lazy-evaluation unit-type semantics

就像标题中所说的那样:对Haskell函数返回单元进行评估有什么保证?有人会认为在这种情况下无需运行任何类型的评估,()除非存在明确的严格性要求,否则编译器可以将所有此类调用替换为立即值,在这种情况下,代码可能必须决定是否应返回()或底部。
我已经在GHCi中对此进行了实验,似乎发生了相反的情况,也就是说,似乎正在评估这种功能。一个非常原始的例子是

f :: a -> ()
f _ = undefined
Run Code Online (Sandbox Code Playgroud)

f 1由于存在,评估会引发错误undefined,因此肯定会发生某些评估。但是,尚不清楚评估的深度。有时它看起来像需要评估返回函数的所有调用一样深()。例:

g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
Run Code Online (Sandbox Code Playgroud)

如果使用,此代码将无限循环g (let x = 1:x in x)。但是之后

f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
Run Code Online (Sandbox Code Playgroud)

可用于显示h (f 1)return (),因此在这种情况下,并非所有单位值的子表达式都被求值。这里的一般规则是什么?

ETA:我当然知道懒惰。我在问什么阻止编译器编写者使这种特殊情况变得比平时更懒。

ETA2:示例摘要:GHC似乎与()任何其他类型完全一样,即,似乎存在一个问题,即应该从函数返回该类型的哪个正则值。优化算法似乎并没有滥用这样一个值的事实。

ETA3:当我说Haskell时,我的意思是报告定义的Haskell,而不是GHC中的Haskell。似乎是一个假设没有像我想象的那样广泛共享(这是“ 100%的读者”),或者我可能能够提出一个更明确的问题。即便如此,我还是很遗憾更改了问题的标题,因为它最初询问对调用此函数有什么保证

Wil*_*ess 10

您似乎是基于这样的假设,即类型()只有一个可能的值,()因此期望返回值类型为value的任何函数调用()都应自动假定为确实会产生value ()

这不是Haskell的工作方式。每个类型在Haskell中都有一个值,即没有值,错误或由编码的所谓的“底部” undefined。因此,实际上是在进行评估:

main = print (f 1)
Run Code Online (Sandbox Code Playgroud)

等同于核心语言的

main = _Case (f 1) _Of x -> print x   -- pseudocode illustration
Run Code Online (Sandbox Code Playgroud)

甚至(*)

main = _Case (f 1) _Of x -> putStr "()"
Run Code Online (Sandbox Code Playgroud)

和核心的_Case强迫

“对%case[expression]求值会强制对要测试的表达式(“ scrutinee”)进行求值。scrutinee的值绑定到%of关键字... 之后的变量。”

该值被强制为弱磁头正常形式。这是语言定义的一部分。

Haskell是不是一个声明编程语言。


(*) print x = putStr (show x)show () = "()",因此show可以完全将调用编译掉。

该值的确预先称为(),甚至的值show ()也预先称为"()"。仍然接受的Haskell语义要求(f 1)在继续打印预先已知的字符串之前,必须将的值强制设为弱头范式"()"


编辑:考虑concat (repeat [])。应该是[]还是应该是无限循环?

一种“声明性语言”对此的答案很可能是[]。Haskell的答案是无限循环

懒惰 “穷人的声明式编程”,但这仍然不是真实的东西

edit2print $ h (f 1) == _Case (h (f 1)) _Of () -> print ()并且仅h是强制的,不是f;并产生回答h不必强求什么,根据它的定义h _ = ()

分开的话:懒惰可能有存在的理由,但这不是它的定义。懒惰就是它。它被定义为所有最初是thunk的值,根据来自的要求被强制为WHNF main。如果它有助于根据特定情况在特定情况下避免触底反弹,那么它可以做到。如果没有,那就没有。就这些。

它可以帮助您自己以自己喜欢的语言来实现它,以使自己有一种感觉。但是,我们也可以通过仔细命名所有临时值来跟踪任何表达式的评估。

  • 我喜欢你的解释。这很简单。 (2认同)