F # условные выражения if ... then..еще возвращаясь блок или ()

условные выражения 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 возвращается?

4 ответов


рассмотрим следующий код:

let f a = if a > 5 then true

если вы называете f 10 возвращает true.

теперь спросите себя: что должно f 2 вернуться? Я знаю, ты скажешь false, но откуда компилятор знает, что? Я имею в виду, это так же вероятно, что вы хотели, чтобы он вернулся true в обоих случаях, не так ли? Или даже, возможно, врезаться в a <= 5 случае, кто знает?

Итак, чтобы программа была "полной" (т. е. содержала инструкции для того, что делать в каждой ситуации), вы всегда должны указать else филиала.


unit, однако,специальные.

возвращение unit означает, что нет значимого возвращаемого значения. По существу unit означает побочный эффект: это означает, что вещь, которая вернула его, должна была произвести некоторый эффект во внешнем мире. Поскольку F# не является чистым языком, такой unit-возвращение вещи довольно вездесущи. Например, отладка logging:

let f x =
    if x < 42 then printfn "Something fishy, x = %d" x
    x + 5

С такими утверждениями нет никакой двусмысленности: всегда известно, что else ветка предназначена для возврата () как хорошо. В конце концов, других значений unit, там? В то же время, всегда добавляем else () в конце было бы очень утомительно и запутанно. Таким образом, в интересах удобства использования компилятор не требует else филиал в этом конкретном случае.


В F# if является выражением, а не утверждением. Каждое выражение должно возвращать значение. А как if и else необходимо вернуть тот же тип значения, потому что F# является строго типизированным языком. Так что, если нет else ветвь, то по умолчанию она имеет тип unit, а если if возвращает значение типаunit, тогда вам нужно иметь else С тем же типом.


типы значений, производимых в каждой ветви, должны совпадать. Если нет явной ветви else, ее тип-unit. Поэтому, если тип ветви then является любым типом, отличным от unit, должна быть ветвь else с тем же типом возврата.

если убрать else из первого фрагмента, это эквивалентно

let x = 
    if ("hello" = null) 
    then true
    else ()

не typecheck.

почему? Я бы предположил, для совместимости с Программирования OCaml

на else expr3 часть может быть опущена, и в этом случае она по умолчанию else (). (7.7.2)

вы можете думать о unit-возвратить if как эквивалент C-like if сообщении в отличие от выражения.


вопрос уже ответил, поэтому я просто собираюсь продолжить свои собственные поверхностные наблюдения

в F# у нас нет операторов и выражений. В F# мы составляем вычисления, используя только выражения. Это хороший вещь.

в C#, где if это утверждение имеет смысл

if(x)
{
  return 1;
}

если x истинно выполнение остановлено, и мы возвращаем вызывающему результат: 1.

в F#, где if выражение это означает, что if должен представлять ценность независимо от того, какая ветвь была взята. Поэтому это имеет мало смысла

if x then 1 // What value should else branch evaluate to?

мы должны указать обе ветви

if x then 1 else 0

как показывают другие ответы, существует особый случай, когда else опущен. The if выражение произведет unit value, самое близкое, что мы получаем к оператору в 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