与えられた結果の型
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 でエラーを返すようにするにはどうすればよいですか?
- async を mymonad でラップするように関数 d を作成するにはどうすればよいですか?
- Async と同様の方法でモナドをパラメータ化するにはどうすればよいですか?
...私が書くことができるように
let f (a:MyMonad<int>) (b:MyMonad<string>) = ...
アップデート:
また、いくつかの mymonad 操作を並行して実行し、結果の配列を見て、エラーと成功の内容を確認したいと考えています。このため、例外を使用することはお勧めできません。
また、質問3に関して、私が意味したのは、呼び出し元が非同期を扱っていることを知らない/気にしないように、型をパラメーター化して不透明にすることでした。私がモナドを書いた方法では、呼び出し元は常に Async.RunSynchronously を使用して mymonad 式を実行できます。
更新 2:
これまでのところ、次のようになりました。
- MyMonadBuilder の各メンバーに明示的な型を使用します
- ReturnFrom を MyMonadBuilder に追加しました。この関数を使用して Async< Result<'t> > をラップします
- エラー値で mymonad を作成する failwith のようなヘルパー関数を追加しました
コードは次のようになります。
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
これは私の目的にはかなり良いようです。ありがとう!