Нужно ли использовать ветвь else в асинхронных выражениях?

Я хочу написать следующий код:

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, через расширение к модулю или как-то так.


person Rustam    schedule 07.04.2014    source источник


Ответы (2)


Между построителем вычислений async и моим построителем imperative есть важное различие.

В async вы не можете создать полезное вычисление, которое не возвращает значение. Это означает, что Async<'T> представляет собой вычисление, которое в конечном итоге даст значение типа 'T. В этом случае метод async.Zero должен возвращать unit и иметь сигнатуру:

async.Zero : unit -> Async<unit>

Для imperiatve builder тип 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.

person Tomas Petricek    schedule 07.04.2014
comment
Это то, что я предполагал. Но у меня была надежда, что может быть какой-то короткий путь, который поможет. Тем не менее, благодаря вашему примеру imperative я создал свой собственный рабочий процесс, который сочетает его с async. Может не очень плавно, но работает нормально. - person Rustam; 07.04.2014
comment
@Rustam - мне было бы любопытно - ты определил свой собственный тип вычислений? Я думаю, что невозможно определить второй тип метода Zero для стандартных асинхронных операций... - person Tomas Petricek; 08.04.2014
comment
Да, я использовал ваш пример и также включил в него async в качестве вторичного вида вычислений. Вот он: gist.github.com/GusRustam/10081383 Я не уверен, что этот код полностью безопасен, но в настоящее время он работает для меня. - person Rustam; 08.04.2014

Я думаю, что эта ситуация описана здесь: Условные выражения: если... иначе (F#)

(...) если тип ветви then является любым типом, отличным от unit, должна быть ветвь else с тем же типом возвращаемого значения.

В вашем первом коде нет ветки else, что вызвало ошибку.

person MarcinJuraszek    schedule 07.04.2014
comment
Интересно... Я был уверен, что видел, как такие конструкции if xxx then return false использовались в пользовательских выражениях вычислений, и я просто хотел проверить, может ли это работать и в async. Я проверю дважды... - person Rustam; 07.04.2014
comment
См. раздел Пример из реальной жизни. - person Rustam; 07.04.2014
comment
@Rustam - Это одна из тех вещей, которые вы можете сделать, но, вероятно, это плохая идея, если вы действительно не знаете, что делаете. - person John Palmer; 07.04.2014
comment
@JohnPalmer Ну, я нахожу вычислительное выражение очень мощным инструментом, но действительно немного надуманным. Несмотря на это, я предпочел бы попытаться привыкнуть к ним. - person Rustam; 07.04.2014
comment
Что ж, эта цитата относится только к обычным выражениям if .. then .. else, не находящимся внутри блока вычислительных выражений. Внутри вычислительных выражений ситуация более тонкая и зависит от того, как определены члены Zero и Combine. Подробнее см.: tomasp.net/academic/papers/computation-zoo. - person Tomas Petricek; 07.04.2014