2012-04-18 10 views
6

dire che ho scritto il seguente pezzo amazin di codice:"<-" e valori associati

func = do 
    a <- Just 5 
    return a 

E 'abbastanza inutile, lo so. Qui, a è 5 e func restituisce Just 5.

Ora riscrivo la mia funzione impressionante (ancora inutile):

func' = do 
    a <- Nothing 
    return a 

Questa funzione restituisce Nothing, ma che diamine è a? Non c'è niente da estrarre da un valore Nothing, ma il programma non lamentele dei giocatori quando faccio qualcosa di simile:

func'' = do 
    a <- Nothing 
    b <- Just 5 
    return $ a+b 

ho solo una difficoltà a vedere ciò che effettivamente accade. Che cos'è a? In altre parole: cosa fa lo <-in realtà? Dicendolo "estrae il valore dal lato destro e lo lega al lato sinistro" è ovviamente troppo semplicistico. Cosa non sto ottenendo?

Grazie :)

+1

'<-' si traduce in' >> = '. Nel caso di 'Maybe' monad, se il primo argomento (cioè la parte destra di' <-') è 'Nothing', nient'altro viene valutato e' >> = 'restituisce' Nothing'. Quindi, per rispondere alla tua domanda: l'esecuzione non ha nemmeno _reach_ 'a'. – Vitus

+0

Pensando a monadi come contenitori, la notazione consente di assegnare etichette ai valori (se presenti) all'interno delle monadi e quindi definire le funzioni da applicare a tali valori. Ma l'estrazione è un'illusione - le funzioni sono applicate all'interno della monade (usando '>> =') perché non esiste un modo generale per estrarre un valore da una monade. Si noti come si termina ogni blocco di do inserendo il risultato _back nella monade_, spesso usando 'return'. Non hai mai avuto una variabile 'a' uguale a 5. – Nefrubyr

risposta

11

Cerchiamo di desugar il fai-notazione che ultimo esempio.

func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b)) 

Ora, vediamo come >> = è definito per Forse. E 'nel Preludio:

instance Monad Maybe where 
    (Just x) >>= k = k x 
    Nothing >>= k = Nothing 
    return   = Just 
    fail s   = Nothing 

Così Nothing >>= foo è semplicemente Nothing

+0

Grazie :) Immagino di non essere molto bravo nel dougaring della notazione ... – Undreren

+1

Ogni foo <- barra segue la barra dello schema >> = (\ pippo -> ...). Ora puoi anche vedere perché ci deve essere un'espressione alla fine di ogni do-block, o una di quelle espressioni lambda (possibilmente annidate) avrebbe un corpo di funzione vuoto. Forse questo link aiuterà: http://book.realworldhaskell.org/read/monads.html#monads.do – Sarah

5

Diamo un'occhiata alla definizione di Maybe monade.

instance Monad Maybe where 
    return = Just 

    Just a >>= f = f a 
    Nothing >>= _ = Nothing 

E desugar il do -notation nella funzione:

func' = 
    Nothing >>= \a -> 
    return a 

Il primo argomento di >>= è Nothing e dalla definizione di cui sopra possiamo vedere che >>= solo ignora il secondo argomento. Così otteniamo:

func' = Nothing 

Poiché la funzione \a -> ... viene mai chiamato, a non viene assegnato. Quindi la risposta è: a non è nemmeno raggiunto.


Per quanto riguarda Dezuccheraggio do -notation, ecco un rapido schizzo di come si fa (c'è una semplificazione che ho fatto - la gestione di fail, vale a dire i modelli che non corrispondono):

do {a; rest} → a >> do rest 

Si noti che >> viene solitamente implementato in termini di >>= come a >>= \_ -> do rest (ovvero la seconda funzione ignora semplicemente l'argomento).

do {p <- a; rest} → a >>= \p -> do rest 

do {let x = a; rest} → let x = a in do rest 

E infine:

do {a} = a 

Ecco un esempio:

main = do 
    name <- getLine 
    let msg = "Hello " ++ name 
    putStrLn msg 
    putStrLn "Good bye!" 

desugars a:

main = 
    getLine >>= \name -> 
    let msg = "Hello " ++ name in 
    putStrLn msg >> 
    putStrLn "Good bye!" 

e T o lo rendono completo per coloro che sono curiosi, ecco la traduzione "diritto" di do {p <- a; rest} (presa direttamente dalla relazione Haskell):

do {pattern <- a; rest} → let ok pattern = do rest 
           ok _  = fail "error message" 
          in a >>= ok 
6

La risposta sta nella definizione del Monad istanza di Maybe:

instance Monad Maybe where 
    (Just x) >>= k  = k x 
    Nothing >>= _  = Nothing 
    (Just _) >> k  = k 
    Nothing >> _  = Nothing 
    return    = Just 

vostro func'' si traduce in:

Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b)))) 

Dalla definizione di (>>=) puoi vedere che il primo Nothing è appena passato al risultato.

2

Nothing in realtà non è "niente", in realtà è un possibile valore di qualcosa nel Maybe Monade:

data Maybe t = Nothing | Just t 

Cioè, se avete qualcosa di tipo Maybe t per un certo tipo t, può avere il valore Just x (dove x è qualsiasi tipo di tipo t) oNothing; in questo senso Maybe si estende appena t per avere un altro valore possibile, Nothing. (Ha altre proprietà perché è un monad, ma che in realtà non ci riguardano qui, tranne che per lo zucchero sintattico di do e <-.)

1

Prendiamo il tuo esempio:

func = do 
    a <- Just 5 
    return a 

proprio come in altri linguaggi di programmazione che puoi suddividere in due pezzi corrispondono a "cosa è stato fatto fino ad ora" e "cosa è ancora da fare". Per esempio possiamo fare la rottura tra Just 5 e

a <- ... 
return a 

In molti linguaggi di programmazione popolari ci si aspetta il Just 5 per essere farcito nella variabile a e il codice sarebbe continuata.

Haskell fa qualcosa di diverso. Il "resto del codice" può essere pensato come una funzione che descrive cosa si farebbe con a se si avesse un valore da inserire. Questa funzione viene quindi applicata a Just 5. Ma non è applicato direttamente. Viene applicato utilizzando qualsiasi definizione di >>=, a seconda del tipo di espressione. Per Maybe, >>= è definito in modo che quando si ha a che fare con Just X, la funzione "resto del codice" viene applicata a X.Ma è anche definito in modo che quando si ha a che fare con Nothing la funzione "resto del codice" viene semplicemente ignorata e viene restituito Nothing.

Ora possiamo interpretare il vostro altro esempio

func'' = do 
    a <- Nothing 
    b <- Just 5 
    return $ a+b 

Pausa in Nothing e:

a <- ... 
    b <- Just 5 
    return $ a+b 

Come ho già detto in precedenza, questo blocco di codice può essere pensata una funzione applicata ad un possibile valore di a. Ma viene utilizzato con Nothing e in questo caso è stato definito >>= per ignorare il "resto del codice" e restituire semplicemente Nothing. E questo è il risultato che hai ottenuto.

Problemi correlati