`if-then-else`(总是)可以被函数调用代替吗?
Could `if-then-else` (always) be replaced by a function call?
这个问题是出于对 PL 是如何工作的好奇,而不是其他任何东西。 (它实际上是在查看与 Haskell 不同的 SML 时想到的,因为前者使用按值调用 - 但我的问题是关于 Haskell。)
Haskell (据我了解)具有 "call-by-need" 语义。
这是否意味着如果我定义一个函数如下:
cond True thenExp elseExp = thenExp
cond _ thenExp elseExp = elseExp
这将始终表现得与 if-then-else 表达式完全一样?
或者,从另一种意义上说,if-then-else 是否可以被视为可以定义为函数的东西的语法糖?
编辑:
为了对比 Haskell 与标准 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 中有推迟参数评估的聪明方法(不知道,因为我还不太熟悉)但关键是在按值调用类型的语言中,if-then -else 通常表现不同。
我的问题是这(按需调用与按值调用)是否是这种差异背后的主要原因(共识似乎是 "yes")。
是的,惰性语言只会在需要时才对表达式求值。因此,将表达式的 then/else 部分转换为函数参数是没有问题的。
这与 Idris 或 OCaml 等严格的语言不同,在这些语言中,函数调用的参数在执行被调用函数之前进行评估。
如 Haskell Wikipedia on if-then-else
所说:
For processing conditions, the `if-then-else` **syntax was defined in Haskell98**. However it could be simply replaced by the function `if'`
with
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y
所以如果我们使用上面的 if'
函数,我们 需要评估它 (因为 Haskell 是惰性的,我们不需要评估 if
-then
-else
表达式),Haskell 将首先评估第一个操作数以确定它是 True
还是 False
.如果是True
,它将return第一个表达式,如果是False
,它将return第二个表达式。请注意,这本身 not 意味着我们(完全)评估这些表达式。只有当我们需要结果时,我们才会计算表达式。
但如果条件是 True
,则根本没有理由计算第二个表达式,因为我们忽略了它。
如果我们在表达式树的多个部分共享一个表达式,另一个调用当然有可能(部分)计算另一个表达式。
ghci
甚至可以选择覆盖 if <expr> then <expr> else <expr>
语法:-XRebindable
标志。它会,除此之外还有:
Conditionals (e.g. if e1 then e2 else e3
) means ifThenElse e1 e2 e3
. However case expressions are unaffected.
是的,你可以把if/then/else
当成语法糖。事实上,编程语言甚至不需要布尔值,所以你也可以把True
和False
当作语法糖。
lambda calculus 将布尔值定义为一组带有两个参数的函数:
true = λt.λf.t
false = λt.λf.f
这两个函数都是取两个值的函数,t
代表true,f
代表false .函数 true
总是 returns t
值,而函数 false
总是 returns 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。
这个问题是出于对 PL 是如何工作的好奇,而不是其他任何东西。 (它实际上是在查看与 Haskell 不同的 SML 时想到的,因为前者使用按值调用 - 但我的问题是关于 Haskell。)
Haskell (据我了解)具有 "call-by-need" 语义。 这是否意味着如果我定义一个函数如下:
cond True thenExp elseExp = thenExp
cond _ thenExp elseExp = elseExp
这将始终表现得与 if-then-else 表达式完全一样? 或者,从另一种意义上说,if-then-else 是否可以被视为可以定义为函数的东西的语法糖?
编辑:
为了对比 Haskell 与标准 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 中有推迟参数评估的聪明方法(不知道,因为我还不太熟悉)但关键是在按值调用类型的语言中,if-then -else 通常表现不同。 我的问题是这(按需调用与按值调用)是否是这种差异背后的主要原因(共识似乎是 "yes")。
是的,惰性语言只会在需要时才对表达式求值。因此,将表达式的 then/else 部分转换为函数参数是没有问题的。
这与 Idris 或 OCaml 等严格的语言不同,在这些语言中,函数调用的参数在执行被调用函数之前进行评估。
如 Haskell Wikipedia on if-then-else
所说:
For processing conditions, the `if-then-else` **syntax was defined in Haskell98**. However it could be simply replaced by the function `if'` withif' :: Bool -> a -> a -> a if' True x _ = x if' False _ y = y
所以如果我们使用上面的 if'
函数,我们 需要评估它 (因为 Haskell 是惰性的,我们不需要评估 if
-then
-else
表达式),Haskell 将首先评估第一个操作数以确定它是 True
还是 False
.如果是True
,它将return第一个表达式,如果是False
,它将return第二个表达式。请注意,这本身 not 意味着我们(完全)评估这些表达式。只有当我们需要结果时,我们才会计算表达式。
但如果条件是 True
,则根本没有理由计算第二个表达式,因为我们忽略了它。
如果我们在表达式树的多个部分共享一个表达式,另一个调用当然有可能(部分)计算另一个表达式。
ghci
甚至可以选择覆盖 if <expr> then <expr> else <expr>
语法:-XRebindable
标志。它会,除此之外还有:
Conditionals (e.g.
if e1 then e2 else e3
) meansifThenElse e1 e2 e3
. However case expressions are unaffected.
是的,你可以把if/then/else
当成语法糖。事实上,编程语言甚至不需要布尔值,所以你也可以把True
和False
当作语法糖。
lambda calculus 将布尔值定义为一组带有两个参数的函数:
true = λt.λf.t
false = λt.λf.f
这两个函数都是取两个值的函数,t
代表true,f
代表false .函数 true
总是 returns t
值,而函数 false
总是 returns 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。