2015-06-07 11 views
5

Sto eseguendo GHC versione 7.8.3 su Windows 7.Come utilizzare correttamente le espressioni monadiche in Haskell senza ottenere errori di analisi?

Ok, non si tratta di frammenti di codice di fantasia. Sto solo cercando di non essere un noob qui e in realtà compilo qualcosa in un modo che assomiglia vagamente alla struttura dei linguaggi di effetti collaterali.

Ho il codice seguente:

main = 
    do { 
    let x = [0..10]; 
    print x 
} 

I've learned here, che la parola chiave fare è uno zucchero sintattico di fantasia per le espressioni monadici fantasia. Quando provo a compilare, ottengo il seguente errore:

main.hs:4:1: parse error on input 'print' 

E ho imparato a this other question, che le schede a Haskell sono il male, così ho cercato di omettere loro:

main = 
    do { 
let x = [0..10]; 
print x 
} 

E ho fallito miseramente, perché l'errore di analisi persiste.

I've also learned here, che la stampa è uno zucchero sintattico per l'equivalente di fantasia:

main = 
    do { 
    let x = [0..10]; 
    putStrLn $ show x 
} 

Ma allora ottengo questo errore invece:

main.hs:4:9: parse error on input 'putStrLn' 

Cercando di affrontare la mia disperazione, ho cercato di omettere la parola chiave let, after reading this answer:

main = 
    do { 
    x = [0..10]; 
    print x 
} 

E allora ottengo:

main.hs:4:1: parse error on input '=' 

E in un inutile tentativo finale, ho anche cercato di omettere il ';' in questo modo:

main = 
    do { 
    let x = [0..10] 
    print x 
} 

E preso:

main.hs:4:1: parse error on input 'print' 

Quindi,

Come usare correttamente le espressioni monadici a Haskell senza ottenere errori di analisi? C'è qualche speranza?

+3

Se si utilizza parentesi esplicite sembra il parser richiede l' 'tale dicitura nella dichiarazione let. Quindi 'do {let x = 10; print x} 'non funziona ma' do {let x = 10 in print x} 'fa. In alternativa, ometti le parentesi e puoi omettere il 'in'. – user2407038

risposta

4
main = do let x = [0..10] 
      print x 

funziona per me

e così fa

main = do { let x = [0..10] 
      in print x } 

Penso che si sta cercando di mescolare alcuni diverse opzioni di sintassi up.

5

Stavo per dire, senza alcuna informazione utile, che

main = do 
    let x = [0..10] 
    print x 

stava lavorando per me, ma sono ora fuori per leggere il in all'interno delle parentesi.

Come una piccola parte, ho trovato http://echo.rsmw.net/n00bfaq.html piuttosto utile per la lettura di identificazione/formattazione.

15

Mi c'è voluto un po 'per vedere cosa stava realmente succedendo qui:

main = 
    do { 
    let x = [0..10]; 
    print x 
} 

L'aspetto di cui sopra, come se abbiamo un do con due affermazioni, che è perfettamente bene. Certo, non è pratica comune utilizzare parentesi graffe e punti e virgola quando il rientro li inserisce implicitamente. Ma loro non dovrebbero ferire ... perché allora l'analisi di cui sopra non riesce?

Il vero problema è che let apre un nuovo blocco! Il blocco let non ha parentesi, quindi si applica la regola di indentazione. Il blocco inizia con la definizione x = [0..10]. Quindi viene trovato un punto e virgola, che promette di seguire un'altra definizione, ad es.

let x = [0..10] ; y = ... 

o anche

let x = [0..10] ; 
     y = ...  -- must be indented as the x above, or more indented 

Tuttavia, dopo il punto e virgola troviamo print, che è ancora rientrato meno di x. Secondo la regola indentazione, questo equivale a inserire parentesi come:

main = 
    do { 
    let { x = [0..10]; } 
    print x 
} 

ma quanto sopra non analizza. Il messaggio di errore non si riferisce alle parentesi inserite implicitamente (che sarebbe molto confuso!), Ma solo alla riga successiva (sfortunatamente in questo caso, sfortunatamente).

Il codice può essere risolto ad es. fornendo sostegni espliciti per let:

main = do { let { x = [0..10] }; 
      print x } 

Sopra, il rientro è del tutto irrilevante: è possibile aggiungere interruzioni di riga e/o spazi senza influenzare l'analisi (ad esempio come in Java, C, ecc). In alternativa, si può spostare la virgola di seguito:

main = do { let x = [0..10] 
      ; print x } 

Quanto sopra virgola è sulla riga successiva ed è meno frastagliata di x, implicitamente inserendo un } che chiude il blocco let. Qui l'indentazione è importante, dal momento che let utilizza la regola dell'indentazione. Se rientichiamo di più il punto e virgola, possiamo causare lo stesso errore di analisi che abbiamo trovato in precedenza.

Naturalmente, la scelta più idiomatica sta usando la regola rientro per l'intero codice:

main = do let x = [0..10] 
      print x 
+2

Ottima risposta, sono molto nuovo per Haskell (motivo per cui sto sfogliando le domande su SO) e questo mi ha aiutato a riempire gli spazi vuoti. – Chris

+0

Molto, molto buono! Sì, è stato molto utile, e ora lo capisco completamente (e aiuterà gli altri anime persi là fuori in futuro) –

+0

Se non avessi passato solo un mese a leggere il Rapporto, anch'io non avrei idea di cosa stai parlando di ... Ben giocato! – MathematicalOrchid

Problemi correlati