2012-05-04 16 views
17

So che èScala equivalente di do-la notazione di Haskell (ancora una volta)

do 
    x <- [1, 2, 3] 
    y <- [7, 8, 9] 
    let z = (x + y) 
    return z 

può essere espressa in Scala come

for { 
    x <- List(1, 2, 3) 
    y <- List(7, 8, 9) 
    z = x + y 
} yield z 

Ma, soprattutto con monadi Haskell, Haskell ha spesso istruzioni all'interno del do blocco che non corrisponde a <- o =. Ad esempio, ecco un codice di Pandoc che utilizza Parsec per analizzare qualcosa da una stringa.

-- | Parse contents of 'str' using 'parser' and return result. 
parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a 
parseFromString parser str = do 
    oldPos <- getPosition 
    oldInput <- getInput 
    setInput str 
    result <- parser 
    setInput oldInput 
    setPosition oldPos 
    return result 

Come si può vedere, si salva la posizione e l'ingresso, corre il parser sulla corda, e poi ripristina l'ingresso e la posizione prima di restituire il risultato.

Non riesco, per la vita di me, a capire come tradurre setInput str, setInput oldInput e setPosition oldPos in Scala. Penso che avrebbe funzionato se ho appena messo le variabili senza senso in modo da poter utilizzare <-, come

for { 
    oldPos <- getPosition 
    oldInput <- getInput 
    whyAmIHere <- setInput str 
    result <- parser 
    ... 
} yield result 

ma non sono sicuro che sia il caso e, se è corretto, sono sicuro che ci deve essere un modo migliore per farlo.

Oh, e se puoi rispondere a questa domanda, puoi rispondere ancora una volta: per quanto tempo devo fissare Monads prima che non sentano la magia nera? :-)

Grazie! Todd

+7

Se non si pianifica l'uso della variabile, è possibile sostituirlo con il carattere di sottolineatura: '_ <- setInput str' – incrop

+0

Immagino che sia il modo più simile a Scala di farlo. – TOB

+0

Non sono sicuro che sarebbe effettivamente possibile, ma questo potrebbe sembrare più naturale spostando queste affermazioni nel corpo del for, dove si può davvero andare a uno stile procedurale. – dividebyzero

risposta

24

Sì, quella traduzione è valida.

do { x <- m; n } equivale a m >>= \x -> n e do { m; n } equivale a m >> n. Poiché m >> n è definito come m >>= \_ -> n (dove _ significa "non associare questo valore a qualsiasi cosa"), questa è effettivamente una traduzione valida; do { m; n } corrisponde a do { _ <- m; n } o do { unusedVariable <- m; n }.

Una dichiarazione senza vincolo di variabile in un blocco do ignora semplicemente il risultato, in genere perché non c'è alcun risultato significativo di cui parlare. Ad esempio, non c'è niente di interessante da fare con il risultato di putStrLn "Hello, world!", quindi non vincolerai il risultato a una variabile.

(Per quanto riguarda le monadi come magia nera, la migliore realizzazione che si può avere è che non sono affatto complicate, cercare di trovare un significato più profondo in esse non è generalmente un modo produttivo di imparare come funzionano. Semplicemente un'interfaccia per comporre calcoli che sono particolarmente comuni.Ti consiglio di leggere lo Typeclassopedia per ottenere una solida comprensione dei modelli astratti di Haskell, anche se avrai bisogno di leggere un'introduzione generale di Haskell per trarne molto.)

+1

Qualche idea sul perché Scala non fornisce zucchero per '>>'? –

+0

Penso che scala fornisce una comprensione monade nella forma di per. Forse l'ordine dei calcoli non viene mantenuto. Modifica: non importa che sembra essere mantenuto. –

+1

La risposta su Monad è davvero buona. È solo un modello di programmazione. Niente di molto "magia nera". –