F#的条件表达式需要检查的条件,为true的分支和为false的分支。例如:
let x =
if ("hello" = null)
then true
else false //error if else branch missing
但是,当涉及到unit
,又名()
时,事情会变得很奇怪。
let y =
if ("hello" = null)
then raise <| new ArgumentNullException()
else () //happy with or without else branch
更简单地:
let z =
if ("hello" = null)
then ()
else () //happy with or without else branch
为什么返回else
时不需要unit
分支?
答案 0 :(得分:9)
考虑以下代码:
let f a = if a > 5 then true
如果您呼叫f 10
,它将返回true
。
现在,问问自己:f 2
应该返回什么?我知道您会说false
,但是编译器怎么知道呢?我的意思是,这两种情况下您都可能返回true
,不是吗?甚至在a <= 5
情况下崩溃,谁知道?
因此,为了使程序“完成”(即包含每种情况下的操作说明),必须始终指定一个else
分支。
unit
是特殊。
返回unit
表示没有有意义的返回值。本质上unit
代表副作用:这意味着返回的东西是要在外部世界产生某种影响的。由于F#不是一种纯语言,因此返回unit
的事情非常普遍。例如,调试日志记录:
let f x =
if x < 42 then printfn "Something fishy, x = %d" x
x + 5
有了这样的语句,就没有歧义:众所周知,else
分支也要返回()
。毕竟,unit
没有其他值了吗?同时,始终在末尾添加else ()
会很麻烦且令人困惑。因此,出于可用性的考虑,在这种特定情况下,编译器不需要else
分支。
答案 1 :(得分:2)
在F#中,if
是表达式而不是语句。每个表达式都需要返回一个值。并且if
和else
都需要返回相同类型的值,因为F#是强类型语言。因此,如果没有else
分支,则默认情况下其分支类型为unit
,但是如果您的if
返回的类型不是unit
,则您需要具有相同类型的else
。
答案 2 :(得分:1)
如果您从第一个片段中删除else
,则相当于
let x =
if ("hello" = null)
then true
else ()
不进行类型检查。
为什么?我猜想与OCaml兼容。
The
else expr3
part can be omitted, in which case it defaults toelse ()
. (7.7.2)
您可以将unit
返回if
等同于类似于C的if
语句,而不是表达式。
答案 3 :(得分:1)
问题已经回答,所以我将继续进行自己的肤浅观察
在F#中,我们没有语句和表达式。在F#中,我们仅使用表达式进行计算。这是一件好的事情。
在C#中,if
是一条有意义的语句
if(x)
{
return 1;
}
如果x
为true,则停止执行,我们将返回结果返回给调用者:1
。
在F#中,if
是一个表达式,它意味着if
应该产生一个值,而不管采用了哪个分支。因此,这毫无意义
if x then 1 // What value should else branch evaluate to?
我们必须指定两个分支
if x then 1 else 0
其他答案表明,有一种特殊情况是省略else
。 if
表达式将产生一个unit
值,这是我们与F#中的语句最接近的值。
由于if
表达式的类型是单位,因此“ true”分支的类型必须为unit
。
if x then () // This works
if x then () else () // This works
if x then 1 // This won't work, type mismatch