我想写下面的代码:
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
中以某种方式实现。
答案 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