Я пытаюсь узнать немного больше о выражениях вычисления 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 Идея состоит в том, чтобы создать своего рода стек, ориентированный на стек. например 'op {push 2; DUP; add} [] '→' [4] '. –
То, что вы называете 'bind', не является связующим, а просто функцией приложения. Чтобы сделать это монадическим связыванием, вторым параметром должен быть 'op <'b>', а не '' b'. –