Sto cercando di imparare un po 'di più sulle espressioni di calcolo di F # implementando uno dei miei. Tuttavia, ho riscontrato un ostacolo in relazione al metodo Bind
. Ecco quello che ho finora:Implementare il binding in un'espressione di calcolo personalizzata
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()
Ora, la mia comprensione è che tutte le seguenti dovrebbe essere grosso modo equivalente:
// 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 }
I primi 3 sembrano funzionare bene, tuttavia, f4
dà questo errore:
This expression was expected to have type
unit
but here has type
int
ottengo lo stesso errore se uso let
invece di let!
. Tutto ciò che ho letto suggerisce che questo è il modo corretto di implementare Bind
, ma a quanto pare mi manca qualcosa. Qualcuno può far notare cosa sto facendo male?
Che cosa rappresenta questo flusso di lavoro? Ora posso dirti che i tipi di vincoli e di ritorno non sono all'altezza, almeno per quanto riguarda il legame e il ritorno monadici, ma non ho idea di cosa sto guardando. – scrwtp
@scrwtp L'idea è di creare una sorta di DSL stack-oriented. per esempio. 'op {push 2; dup; aggiungi} [] '→' [4] '. –
Quello che chiami 'bind' non è un binding, ma solo una funzione. Per renderlo un binding monadico, il secondo parametro dovrebbe essere 'op <'b>', non ''b'. –