La definizione siete alla ricerca di qualcosa di simile si legge
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) f))
Come siamo arrivati qui? Come sempre, lasciamo che i tipi facciano il lavoro. :)
Vediamo prima di introdurre una funzione di supporto:
runConcurrent :: Concurrent b -> (b -> Action) -> Action
runConcurrent (Concurrent h) = h
Se si inizia con il lato sinistro della definizione
Concurrent h >>= k = ...
con h :: (a -> Action) -> Action
e k :: a -> Concurrent b
, allora il vostro obiettivo è sostituire ...
con un'espressione di tipo Concurrent b
, non è vero?
Come è possibile creare un valore di tipo Concurrent b
? Un modo è quello di applicare la nostra funzione k
, ma ciò non funzionerà, perché non abbiamo un valore adatto di tipo a
disponibile come argomento. Quindi, praticamente l'unica cosa che possiamo fare è applicare il costruttore di dati Concurrent
che è di tipo ((b -> Action) -> Action) -> Concurrent b
.
che dà:
Concurrent h >>= k = Concurrent ...
Ora dobbiamo andare e ci trovare un'espressione di tipo (b -> Action) -> Action
di fornire come argomento per Concurrent
. Sappiamo che le espressioni di tipo funzione può sempre essere costruiti attraverso lambda-astrazione:
Concurrent h >>= k = Concurrent (\f -> ...)
Questo ci dà f :: b -> Action
e l'obbligo di sostituire ...
con un'espressione di tipo Action
. L'uso diretto di uno dei costruttori Action
sarebbe ovviamente un imbroglio;). Per garantire la genericità di (>>=)
(più precisamente, per assicurarsi che finiamo per obbedire alle leggi della monade), trattiamo lo Action
come se fosse un tipo di dati astratto. Quindi, l'unico modo per produrre un Action
-value si applica la funzione h
:
Concurrent h >>= k = Concurrent (\f -> h ...)
Quindi, accanto dobbiamo fornire h
con un argomento di tipo a -> Action
. Che è un tipo di funzione di nuovo, in modo da gettare in un'altra lambda:
Concurrent h >>= k = Concurrent (\f -> h (\x -> ...))
Quindi, abbiamo x :: a
e la necessità di costruire un corpo di tipo Action
. Cosa possiamo fare con un valore di tipo a
?Possiamo fornirlo alla funzione k
. Questo ci dà un valore di tipo Concurrent b
, che possiamo poi passare alla nostra funzione di supporto runConcurrent
:
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) ...))
Questo ci dà una funzione di tipo (b -> Action) -> Action
e fornendo f
come argomento fa il trucco:
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) f))
La tua analisi è sbagliata. 'x' ha tipo' b -> Azione', non 'b'. – bennofs
Si potrebbe voler controllare [Monade gratis] (http://stackoverflow.com/questions/13352205/what-are-free-monads). Ti consente di registrare una monade, che può essere riprodotta arbitrariamente. L'ho usato per fili leggeri. – Franky