Ci sono due modi diversi di attuazione costruttori continuazione in F #. Uno è quello di rappresentare i calcoli ritardati utilizzando il tipo di monade (se supporta un modo di rappresentare i calcoli in ritardo, come Async<'T>
o il tipo unit -> option<'T>
come mostrato dalla CNM.
Tuttavia, è anche possibile utilizzare la flessibilità di F espressioni # di calcolo e l'uso . un diverso tipo come valore di ritorno di Delay
allora avete bisogno di modificare il funzionamento Combine
di conseguenza e anche implementare Run
membro, ma tutto funziona abbastanza bene:
type OptionBuilder() =
member x.Bind(v, f) = Option.bind f v
member x.Return(v) = Some v
member x.Zero() = Some()
member x.Combine(v, f:unit -> _) = Option.bind f v
member x.Delay(f : unit -> 'T) = f
member x.Run(f) = f()
member x.While(cond, f) =
if cond() then x.Bind(f(), fun _ -> x.While(cond, f))
else x.Zero()
let maybe = OptionBuilder()
il trucco è che compilatore F # usa Delay
quando si avere un calcolo che deve essere ritardato - t hat è: 1) per avvolgere l'intero computazione, 2) quando componi sequenzialmente calcoli, ad es.utilizzando if
all'interno del calcolo e 3) per ritardare i corpi di while
o for
.
Nella definizione di cui sopra, l'organo Delay
restituisce unit -> M<'a>
anziché M<'a>
, ma è perfettamente soddisfacente perché Combine
e While
prendono unit -> M<'a>
come loro secondo argomento. Inoltre, aggiungendo Run
che valuta la funzione, il risultato di maybe { .. }
blocco (funzione ritardo) viene valutato, in quanto l'intero blocco viene passato Run
:
// As usual, the type of 'res' is 'Option<int>'
let res = maybe {
// The whole body is passed to `Delay` and then to `Run`
let! a = Some 3
let b = ref 0
while !b < 10 do
let! n = Some() // This body will be delayed & passed to While
incr b
if a = 3 then printfn "got 3"
else printfn "got something else"
// Code following `if` is delayed and passed to Combine
return a }
Questo è un modo per definire builder calcolo per non- tipi ritardati che sono probabilmente più efficienti del tipo di wrapping all'interno di una funzione (come nella soluzione di kkm) e non richiedono la definizione di una versione speciale ritardata del tipo.
Si noti che questo problema non si verifica ad es. Haskell, perché è un linguaggio pigro, quindi non ha bisogno di ritardare i calcoli esplicitamente. Penso che la traduzione F # sia abbastanza elegante in quanto consente di gestire entrambi i tipi ritardati (utilizzando Delay
che restituisce M<'a>
) e tipi che rappresentano solo un risultato immediato (utilizzando Delay
che restituisce una funzione & Run
).
Hai provato a "lasciare il ritardo f = fun() -> f()'? – Daniel
Avete dato un'occhiata all'implementazione di 'Maybe' su monad in FSharpx https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Core/Monad.fs? – pad
Vedere http://stackoverflow.com/questions/4577050/quello-è-il-role-di-sempre-sempre-in-commercamenti-informazioni-in-f per un approccio. – kvb