2014-11-28 9 views
11

Ciao Sto cercando di implementare la Monade della concorrenza di Poor Man. Qui è il mio codice:>> = implementazione per la concorrenza di Poor Man Monad

import Control.Monad 

data Concurrent a = Concurrent ((a -> Action) -> Action) 

data Action 
    = Atom (IO Action) 
    | Fork Action Action 
    | Stop 

instance Monad Concurrent where 
    (Concurrent ma) >>= f = Concurrent (\x -> ma(\y -> "Something return a Action")) 
    return x = Concurrent (\c -> c x) 

Ecco la mia analisi: x ha il tipo di b, y ha il tipo di a, f ha il tipo di (a -> ((b ->Action) -> Action)). Al fine di capire "Qualcosa restituisce un'azione", in primo luogo calcolo (f y), che restituisce un tipo di ((b ->Action) -> Action). Quindi, come può usarlo con x per generare un'azione?

+0

La tua analisi è sbagliata. 'x' ha tipo' b -> Azione', non 'b'. – bennofs

+0

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

risposta

21

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)) 
+0

Funziona. Grazie mille!! –

+0

Tipo di errore del costruttore di dati 'Concurrent' è' ((b -> Action) -> Action) -> Concurrent b' not' ((b -> Action) -> b) -> Concurrent b'. Ho ragione ? – fdelsert

+0

@fdelsert Hai assolutamente ragione. Grazie per averlo individuato. Corretto nella risposta –

Problemi correlati