1

我想编写以下代码:

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通过扩展模块或其他方式以某种方式实现 in 。

4

2 回答 2

3

我认为这里描述了这种情况:条件表达式:if...then...else (F#)

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

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

于 2014-04-07T07:47:20.467 回答
2

async计算生成器和我的生成器之间有一个重要区别imperative

async中,您无法创建不返回值的有用计算。这意味着Async<'T>表示最终将产生类型值的计算'T。在这种情况下,该async.Zero方法必须返回unit并具有签名:

async.Zero : unit -> Async<unit>

对于imperiatvebuilder,类型Imperative<'T>表示可能返回值也可能不返回值的计算。如果你看一下类型声明,它看起来如下:

type Imperative<'T> = unit -> option<'T>

这意味着该Zero操作(当您不使用 编写时使用ifelse可以是任何类型的计算。因此,imperative.Zero方法返回任何类型的计算:

imperative.Zero : unit -> Imperative<'T>

这是一个根本区别,也解释了为什么您可以if在没有else分支的情况下创建(因为该Zero方法可以创建任何类型的计算)。这是不可能的async,因为Zero只能创建unit-returning 值。

所以这两种计算有不同的结构。特别是,“命令式”计算具有单曲面结构,而异步工作流则没有。更多详细信息,您可以在我们的 F# Computation Zoo 论文中找到解释

于 2014-04-07T14:28:48.800 回答