Possiedo un generatore di espressioni di calcolo che crea un valore man mano che si procede e ha molte operazioni personalizzate. Tuttavia, non consente i costrutti del linguaggio F # standard e sto avendo un sacco di problemi nel capire come aggiungere questo supporto.Come si scrive un generatore di espressioni di calcolo che accumula un valore e consente anche costrutti di linguaggio standard?
Per fare un esempio stand-alone, ecco un'espressione di calcolo morto semplice e abbastanza inutile che costruisce F # liste:
type Items<'a> = Items of 'a list
type ListBuilder() =
member x.Yield(()) = Items []
[<CustomOperation("add")>]
member x.Add(Items current, item:'a) =
Items [ yield! current; yield item ]
[<CustomOperation("addMany")>]
member x.AddMany(Items current, items: seq<'a>) =
Items [ yield! current; yield! items ]
let listBuilder = ListBuilder()
let build (Items items) = items
posso usare questo per creare elenchi bene:
let stuff =
listBuilder {
add 1
add 5
add 7
addMany [ 1..10 ]
add 42
}
|> build
Tuttavia, questo è un errore di compilazione:
listBuilder {
let x = 5 * 39
add x
}
// This expression was expected to have type unit, but
// here has type int.
E così è questo:
listBuilder {
for x = 1 to 50 do
add x
}
// This control construct may only be used if the computation expression builder
// defines a For method.
Ho letto tutta la documentazione e gli esempi che riesco a trovare, ma c'è qualcosa che non sto ottenendo. Ogni firma del metodo .Bind()
o .For()
cerco solo di portare a errori del compilatore sempre più confusi. La maggior parte degli esempi che riesco a trovare o costruiscono un valore mentre procedete, o consentono costrutti di linguaggio F # regolari, ma non sono stato in grado di trovarne uno che faccia entrambi.
Se qualcuno mi potrebbe punto nella giusta direzione, mostrandomi come prendere questo esempio e aggiungere il supporto nel generatore per let
attacchi e for
loop (come minimo - using
, while
e try/catch
sarebbe grande, ma posso probabilmente capire quelli fuori se qualcuno mi fa iniziare) quindi sarò in grado di applicare con gratitudine la lezione al mio problema reale.
Grazie per la spiegazione! Penso che la cosa principale che mi mancava era fornire 'Run' per rimuovere il valore trasportato dal valore corrente e l'attributo' ProjectionParameter'. La documentazione sulla scrittura di 'For' e degli altri metodi di builder avrà molto più senso ora che il compilatore non si aspetta che tutto sia 'unit'. –
Ho postato una [domanda di follow-up qui] (http://stackoverflow.com/questions/23144744/why-does-this-computation-expression-builder-expect-unit-in-my-for-loop), se hai tempo per aiutarmi di nuovo a essere meno stupido. –
@kvb, stai seguendo il CE a mano o c'è qualche modo per vedere l'espansione * anche se non si digita il controllo *? –