`if-then-else`(总是)可以用函数调用替换吗?

时间:2018-01-20 11:11:47

标签: haskell lazy-evaluation

这个问题是关于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中的参数评估(不知道我还不熟悉它)但重点是在按值调用的语言中,如果 - 然后 - 其他通常表现不同。 我的问题是这是否(按需求呼叫与价值呼叫)是这种差异背后的主要原因(并且共识似乎是"是")。

3 个答案:

答案 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视为语法糖。实际上,编程语言甚至不需要布尔基元,因此您也可以将TrueFalse视为语法糖。

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中阅读更多内容。