在计算表达式中争用TryWith [英] Wrangling TryWith in Computation expressions
问题描述
(由于无法理解" FParsec,我遵循了我在某处阅读的建议,并开始尝试自己编写一个解析器.不知何故,我发现了看起来有机会尝试对其进行单数化的机会,现在我有了N个问题...)
这是我的结果"类型(简体)
This is my 'Result' type (simplified)
type Result<'a> =
| Success of 'a
| Failure of string
这里是计算表达式生成器
Here's the computation expression builder
type ResultBuilder() =
member m.Return a = Success(a)
member m.Bind(r,fn) =
match r with
| Success(a) -> fn a
| Failure(m) -> Failure(m)
在第一个示例中,一切都按预期工作(编译):
In this first example, everything works (compiles) as expected:
module Parser =
let res = ResultBuilder()
let Combine p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
return fn(x,y) }
我的问题在这里:我希望能够捕捉到合并"函数中的任何失败并返回失败,但是它说我应该定义一个零".
My problem is here: I'd like to be able to catch any failure in the 'combining' function and return a failure, but it says that I should define a 'Zero'.
let Combine2 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
try
return fn(x,y)
with
| ex -> Failure(ex.Message) }
不知道我应该在零中返回什么,我只放入了member m.Zero() = Failure("hello world")
,现在它说我需要TryWith
.
Having no idea what I should return in a Zero, I just threw in member m.Zero() = Failure("hello world")
, and it now says I need TryWith
.
所以:
member m.TryWith(r,fn) =
try
r()
with
| ex -> fn ex
现在它想要延迟,所以member m.Delay f = (fun () -> f())
.
And now it wants Delay, so member m.Delay f = (fun () -> f())
.
这时(在ex -> Failure
上)说This expression should have type 'unit', but has type 'Result<'a>'
,然后我举起手臂转向你们...
At which point it says (on the ex -> Failure
), This expression should have type 'unit', but has type 'Result<'a>'
, and I throw up my arms and turn to you guys...
播放链接: http://dotnetfiddle.net/Ho1sGS
推荐答案
with
块也应从计算表达式返回结果.由于要返回Result.Failure,因此需要定义成员m.ReturnFrom a = a
并使用它从with
块中返回Failure.在try
块中,您还应该指定fn
如果不抛出成功,则返回成功.
The with
block should also return a result from the computation expression. Since you want to return Result.Failure you need to define the member m.ReturnFrom a = a
and use it to return the Failure from the with
block. In the try
block you should also specify that fn
returns Success if it doesn't throw.
let Combine2 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
return!
try
Success(fn(x,y))
with
| ex -> Failure(ex.Message)
}
更新:
原始实现显示警告,而不是错误.自try
块返回以来,未使用with
块中的表达式,因此您可以简单地添加|> ignore
.在这种情况下,如果抛出fn
,则返回值为m.Zero()
,唯一的区别是您将得到"hello world"
而不是ex.Message
.下面举例说明.此处的完整脚本: http://dotnetfiddle.net/mFbeZg
The original implementation was showing a warning, not an error. The expression in the with
block was not used since you returned from the try
block, so you could simply add |> ignore
. In that case if fn
throws then the return value is m.Zero()
and the only difference is that you would get "hello world"
instead of ex.Message
. Illustrated with an example below. Full script here: http://dotnetfiddle.net/mFbeZg
使用|> ignore
来使警告静音的原始实现:
Original implementation with |> ignore
to mute the warning:
let Combine3 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
try
return fn(x,y)
with
| ex -> Failure(ex.Message) |> ignore // no warning
}
运行它:
let comb2 a =
let p1' x = Success(x)
let p2' y = Success(y)
let fn' (x,y) = 1/0 // div by zero
let func = Parser.Combine2 p1' p2' fn' a
func()
let comb3 a =
let p1' x = Success(x)
let p2' y = Success(y)
let fn' (x,y) = 1/0 // div by zero
let func = Parser.Combine3 p1' p2' fn' a
func()
let test2 = comb2 1
let test3 = comb3 1
结果:
val test2 : Result<int> = Failure "Attempted to divide by zero."
val test3 : Result<int> = Failure "hello world"
这篇关于在计算表达式中争用TryWith的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!