是否有必要在异步表达式中使用else分支?

时间:2014-04-07 07:22:51

标签: f# computation-expression

我想写下面的代码:

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。我所要求的确实可能!请查看example,请参阅真实世界示例

部分

我会引用代码:

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 个答案:

答案 0 :(得分:3)

我认为这种情况在这里描述:Conditional Expressions: if... then...else (F#)

  

(...)如果then分支的类型是除unit以外的任何类型,   必须有一个else分支具有相同的返回类型。

您的第一个代码没有else分支,导致错误。

答案 1 :(得分:1)

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 - 返回值。

因此这两个计算具有不同的结构。特别是,“命令式”计算具有单一结构,而异步工作流则不具有。更详细地说,您可以find the explanation in our F# Computation Zoo paper