在Try F#网站上,他们给出了一个计算表达式的例子:
type Age =
| PossiblyAlive of int
| NotAlive
type AgeBuilder() =
member this.Bind(x, f) =
match x with
| PossiblyAlive(x) when x >= 0 && x <= 120 -> f(x)
| _ -> NotAlive
member this.Delay(f) = f()
member this.Return(x) = PossiblyAlive x
let age = new AgeBuilder()
let willBeThere (a:int) (y:int) =
age {
let! current = PossiblyAlive a
let! future = PossiblyAlive (current + y)
return future
}
这看起来有点像在Haskell中找到的标准Maybe monad。
但是,在真正的Haskell形式中,我想使用两行返回:
let! current = PossiblyAlive a
let! future = PossiblyAlive (current + y)
是:
let! current = return a
let! future = return (current + y)
然而它不起作用。我最接近的是:
let! current = age.Return a
let! future = age.Return (current + y)
但这看起来很脏。有没有办法在没有明确使用计算构建器函数的情况下使用return
?
答案 0 :(得分:3)
您可以创建嵌套表达式:
let! current = age { return a }
let! future = age { return (current + y) }
虽然您可以改为使用let
:
let current = a
let future = current + y
请注意,此构建器违反了monad法则
return 150 >>= return
与return 150
答案 1 :(得分:0)
我已经更详细地研究了这个问题,我想我已经找到了一个合理的替代方法来使用Lee在他的答案中显示的age { return <expr> }
语法。
我使用这种语法的主要原因是我们已经在age
monad中,因此正文中的任何return
语句都应自动解析为age.Return
。但是,对于F#团队来说,解决这个问题的可能性非常低,因为解决方法非常简单。
我的另一种方法是使用一个函数重载Bind
方法,该函数取一个然后提升的值;然后将此提升的值发送到另一个Bind
函数:
type Age =
| PossiblyAlive of int
| NotAlive
type AgeBuilder() =
let reasonableAge (x:int) = x >= 0 && x <= 120
member __.Return x =
if reasonableAge x then PossiblyAlive x else NotAlive
member __.Bind(x:Age, f) =
match x with
| PossiblyAlive x when reasonableAge x -> f x
| _ -> NotAlive
member this.Bind(x:int, f) =
this.Bind(this.Return(x), f)
let age = new AgeBuilder()
let willBeThere (a:int) (y:int) =
age {
let! current = a
let! future = (current + y)
return future
}