Важным моментом, который до сих пор не упоминался, является разница между if .. then .. else
и if .. then
без ветви else
.
If
в функциональных языках
Функциональная интерпретация if
заключается в том, что это выражение, которое оценивается до некоторого значенияЧтобы оценить значение if c then e1 else e2
, вы оцениваете условие c
, а затем оцениваете либо e1
, либо e2
, в зависимости от условия.Это дает вам результат if .. then .. else
.
Если у вас просто if c then e
, то вы не знаете, каким должен быть результат оценки, если c
равен false
, потому чтонет else
ветки!Следующее явно не имеет смысла:
let num = if input > 0 then 10
В F # выражения с побочными эффектами, такие как printf "hi"
, возвращают специальное значение типа unit
.Тип имеет только одно значение (записывается как ()
), поэтому вы можете написать if
, который дает эффект только в одном случае:
let u = if input > 0 then printf "hi" else ()
Это всегда оценивается как unit
, нов ветке true
он также выполняет побочный эффект.В ветке false
он просто возвращает значение unit
.В F # вам не нужно писать бит else ()
вручную, но концептуально он все еще там.Вы можете написать:
let u = if input > 0 then printfn "hi"
По поводу вашего дополнительного примера
Код выглядит для меня отлично.Когда вам приходится иметь дело с API, который является императивным (например, с множеством библиотек .NET), тогда лучшим вариантом будет использование таких императивных функций, как if
с unit
-обратной ветвью.
Youможет использовать различные настройки, например, представлять ваши данные, используя option<string>
(вместо просто string
с null
или пустой строкой).Таким образом, вы можете использовать None
для представления отсутствующих данных, а все остальное будет правильным вводом.Затем вы можете использовать некоторые функции более высокого порядка для работы с опциями, например, Option.iter
, который вызывает данную функцию, если есть значение:
maybeData |> Option.iter (fun data ->
let byteData = System.Text.Encoding.Unicode.GetBytes(data)
req.ContentLength <- int64 byteData.Length
use postStream = req.GetRequestStream()
postStream.Write(byteData, 0, byteData.Length) )
Это на самом деле не менее важно, но этоболее декларативный, потому что вам не нужно писать if
самостоятельно.Кстати, я также рекомендую использовать use
, если вы хотите Dispose
объект автоматически.