我想通过实现我自己的一个来更多地了解F#的计算表达式。但是,我已经碰到了与Bind
方法有关的绊脚石。下面是我到目前为止有:在自定义计算表达式中实现绑定
type public op<'a> = Op of ('a list -> 'a list)
let inline (>>) (Op a) (Op b) = Op (a >> b)
module Op =
let id = Op id
let bind (b : 'b -> op<'a>) (v : 'b) = b v
let call (Op f) = f
let push v = Op (fun t -> v :: t)
// .. snip ..
type OpBuilder() =
member __.Bind (v, b) = Op.bind b v
member __.Yield (()) = Op.id
member __.Return (m) = Op.call m
[<CustomOperation("push")>]
member __.Push (m : op<'a>, v : 'a) = m >> Op.push v
// .. snip ..
let op = new OpBuilder()
现在,我的理解是,以下所有的应该是大致相同的:
// Use only the Op module methods
let f1 = Op.call(Op.bind (fun x -> Op.push x) 1)
// Use op builder with external closure
let f2 = Op.call(let x = 2 in op { push x })
// Use op builder bind explicitly
let f3 = op.Return(op.Bind(3, fun x -> op.Push(op.Yield(), x)))
// Use op builder with let! binding
let f4 = op { let! x = 4 in push x }
第3似乎工作正常,但是,f4
给这个错误:
This expression was expected to have type
unit
but here has type
int
我得到同样的错误,如果我用let
代替let!
。我读过的一切都表明,这是实施Bind
的正确方法,但显然我错过了一些东西。任何人都可以指出我做错了什么?
那个工作流程代表什么?我现在可以告诉你,你的绑定和返回的类型是不合格的,至少就一元绑定和返回而言,但我不知道我在看什么。 – scrwtp
@scrwtp这个想法是创建一种面向堆栈的DSL。例如'op {push 2; DUP;添加} []'→'[4]'。 –
你调用'bind'不是一个绑定,而只是函数应用。为了使它成为一元绑定,第二个参数应该是'op <'b>',而不是''b'。 –