给定结果类型
type Result<'t> = OK of 't | Error of string
我有这些函数,它们都返回 Async < Result<'t> >,它们的组合如下:
let a = async { return Result.OK 1000 }
let b = async { return Result.Error "some message" }
let sum x y =
async {
let! r1 = x
match r1 with
| Result.OK v1 ->
let! r2 = y
match r2 with
| Result.OK v2 -> return v1 + v2
| Result.Error msg -> return Result.Error msg
| Result.Error msg -> return Result.Error msg
}
这段代码看起来很糟糕,所以我想要这个:
type Result = Ok of int | Error of string
type MyMonadBuilder() =
member x.Bind (v,f) =
async {
let! r = v
match r with
| Ok r' -> return! f r'
| Error msg -> return Error msg
}
member x.Return v = async {return Ok v }
member x.Delay(f) = f()
let mymonad = MyMonadBuilder()
let runMyMonad = Async.RunSynchronously
let a = mymonad { return 10 }
let b = mymonad { return 20 }
let c =
mymonad {
return Result.Error "Some message"
//??? The above doesn't work but how do I return a failure here?
}
let d =
async {
return Ok 1000
}
//how to wrap this async with mymonad such that I can use it together with my other computation expressions?
let sum x y =
mymonad {
let! v1 = x
let! v2 = y
return v1 + v2
}
[<EntryPoint>]
let main argv =
let v = sum a b |> runMyMonad
match v with
| Ok v' -> printfn "Ok: %A" v'
| Error msg -> printf "Error: %s" msg
System.Console.Read() |> ignore
0
所以问题是:
- 如何编写函数 c 使其在 mymonad 中返回错误?
- 如何编写函数 d 以便它用 mymonad 包装异步?
- 我怎样才能让我的 monad 以类似于 Async 的方式参数化?
...这样我可以写
let f (a:MyMonad<int>) (b:MyMonad<string>) = ...
更新:
此外,我想并行运行几个 mymonad 操作,然后查看结果数组以查看错误和成功之处。出于这个原因,我认为使用异常不是一个好主意。
另外,关于问题 3,我的意思是让我的类型参数化和不透明,以便调用者不知道/不在乎他们正在处理异步。我编写 monad 的方式,调用者总是可以使用 Async.RunSynchronously 来运行 mymonad 表达式。
更新 2:
到目前为止,我最终得到了以下结果:
- 我为 MyMonadBuilder 的每个成员使用显式类型
- 我将 ReturnFrom 添加到 MyMonadBuilder。我使用这个函数来包装一个 Async< Result<'t>>
- 我添加了像 failwith 这样的辅助函数,它创建了一个带有错误值的 mymonad
代码如下所示:
type MyMonad<'t> = 't Result Async
type MyMonadBuilder() =
member x.Bind<'t> (v,f) : MyMonad<'t>=
async {
let! r = v
match r with
| Ok r' -> return! f r'
| Error msg -> return Error msg
}
member x.Return<'t> v : MyMonad<'t> = async {return Ok v }
member x.ReturnFrom<'t> v : MyMonad<'t> = v
member x.Delay(f) = f()
let failwith<'t> : string -> MyMonad<'t> = Result.Error >> async.Return
这对于我的目的来说看起来相当不错。谢谢!