这个问题是关于PL如何工作的好奇心,而不是其他任何问题。 (实际上,我看到的是SML,它与Haskell的不同之处在于前者使用了call-by-value - 但我的问题是关于Haskell。)
Haskell(据我所知)有#34;按需拨打"语义。 这是否意味着如果我按如下方式定义函数:
cond True thenExp elseExp = thenExp
cond _ thenExp elseExp = elseExp
这总是表现得像if-then-else表达式? 或者,从另一个意义上讲,if-then-else是否可以被视为可以被定义为函数的语法糖?
修改
只是为了对比Haskell与Standard ML的行为,定义(在SML中)
cond p t f = if p then t else f;
然后是阶乘函数
fun factc n = cond (n=0) 1 (n * factc (n-1));
评估factc 1(说)永远不会完成,因为cond
的最后一个参数中的递归永远不会终止。
然而,定义
fun fact n = if n=0 then 1 else fact (n-1);
按预期工作,因为then分支仅在需要时进行评估。
也许有一些聪明的方法可以推迟SML中的参数评估(不知道我还不熟悉它)但重点是在按值调用的语言中,如果 - 然后 - 其他通常表现不同。 我的问题是这是否(按需求呼叫与价值呼叫)是这种差异背后的主要原因(并且共识似乎是"是")。
答案 0 :(得分:6)
就像Haskell Wikipedia on if-then-else
说的那样:
对于处理条件,在Haskell98 **中定义了`if-then-else` **语法。然而,它可以简单地用函数“if'”代替 同if' :: Bool -> a -> a -> a if' True x _ = x if' False _ y = y
因此,如果我们使用上述if'
函数,并且需要对其进行评估(因为Haskell很懒,我们无需评估if
- { {1}} - then
表达式,Haskell将首先评估第一个操作数,以确定它是else
还是True
。如果它是False
,它将返回第一个表达式,如果它是True
,它将返回第二个表达式。请注意,这 not 本身意味着我们(完全)评估这些表达式。只有当我们需要结果时,我们才会评估表达式。
但是如果条件为False
,则根本没有理由评估第二个表达式,因为我们忽略它。
如果我们在表达式树的多个部分上共享一个表达式,那么另一个调用当然可以(部分地)计算另一个表达式。
True
甚至可以选择覆盖ghci
语法:-XRebindable
标志。除此之外,它还会:
条件(例如
if <expr> then <expr> else <expr>
)表示if e1 then e2 else e3
。但是案例表达不受影响。
答案 1 :(得分:3)
是的,懒惰语言只会在需要时评估表达式。因此,将表达式的then / else部分转换为函数参数是没有问题的。
这与像Idris或OCaml这样的严格语言不同,其中函数调用的参数在执行被调用函数之前被计算。
答案 2 :(得分:2)
是的,您可以将if/then/else
视为语法糖。实际上,编程语言甚至不需要布尔基元,因此您也可以将True
和False
视为语法糖。
lambda calculus将布尔值定义为一组带有两个参数的函数:
true = λt.λf.t
false = λt.λf.f
这两个函数都是两个值的函数, true 为t
, false 为f
。函数true
始终返回t
值,而函数false
始终返回f
值。
在Haskell中,您可以定义类似的函数:
true = \t f -> t
false = \t f -> f
然后,您可以编写cond
函数,如:
cond = \b t f -> b t f
示例:
Prelude> cond true "foo" "bar"
"foo"
Prelude> cond false "foo" "bar"
"bar"
在Travis Whitaker的文章Scrap Your Constructors: Church Encoding Algebraic Types中阅读更多内容。