Нужно ли использовать еще ветку в асинхронных выражениях?
Я хочу написать следующий код:
let someAsync () = async {
if 1 > 2 then return true // Error "this expression is expected to have type unit ..."
// I want to place much code here
return false
}
F# почему-то считает, что мне нужно написать так:
let someAsync () = async {
if 1 > 2 then return true
else
// Much code here (indented!)
return false
}
В последнем случае сообщение об ошибке не выдается. Но, на мой взгляд, обе части кода эквивалентны. Есть ли шанс, что я смогу избежать ненужных вложений и отступов?
UPD. То, что я спрашиваю, действительно возможно! Пожалуйста, посмотрите на пример, смотрите раздел Пример реального мира.
Я процитирую код:
let validateName(arg:string) = imperative {
if (arg = null) then return false // <- HERE IT IS
let idx = arg.IndexOf(" ")
if (idx = -1) then return false // <- HERE IT IS
// ......
return true
}
Так что, возможно, вопрос только в том, можно ли как-то реализовать в async
через расширение модуля или что-то еще.
2 ответа
Существует важное различие между async
построитель вычислений и мой imperative
строитель.
В async
Вы не можете создать полезное вычисление, которое не возвращает значение. Это означает, что Async<'T>
представляет вычисление, которое в конечном итоге приведет к значению типа 'T
, В этом случае async.Zero
метод должен вернуть unit
и имеет подпись:
async.Zero : unit -> Async<unit>
За imperiatve
строитель, тип Imperative<'T>
представляет вычисление, которое может возвращать или не возвращать значение. Если вы посмотрите на объявление типа, оно выглядит следующим образом:
type Imperative<'T> = unit -> option<'T>
Это означает, что Zero
операция (которая используется, когда вы пишете if
без else
) может быть вычислением любого типа. Так, imperative.Zero
Метод возвращает вычисление любого типа:
imperative.Zero : unit -> Imperative<'T>
Это принципиальная разница, которая также объясняет, почему вы можете создать if
без else
ветвь (потому что Zero
метод может создавать вычисления любого типа). Это невозможно для async
, так как Zero
можно только создать unit
Возврат ценностей.
Таким образом, два вычисления имеют разные структуры. В частности, "императивные" вычисления имеют моноидальную структуру, а асинхронные рабочие процессы - нет. Более подробно вы можете найти объяснение в нашей статье F# Computation Zoo
Я думаю, что ситуация описана здесь: Условные выражения: if... then... else (F#)
(...) если тип
then
ветвь любого типа, кромеunit
должно бытьelse
ветвь с тем же типом возврата.
Ваш первый код не имеет else
ветка, которая вызвала ошибку.