2015-10-08 13 views
5

Lavorare in Haskell, ha trovato strano comportamento, messo a nudo giù alle ossa nudeQuale indentazione è richiesta per un'istruzione case all'interno di una dichiarazione let?

questo funziona

a :: Bool 
a = case True of 
    True -> True 
    False -> False 

Ma quando provo

b :: IO Bool 
b = do 
    let b' = case True of 
     True -> True 
     False -> False 
    return b' 

ottengo

ghci>:l test.hs 
[1 of 1] Compiling Main    (test.hs, interpreted) 

test.hs:16:14: parse error on input ‘->’ 
Failed, modules loaded: none. 

Così Provo

c :: IO Bool 
c = do 
    let c' = case True of 
      True -> True 
      False -> False 
    return c' 

E questo funziona.

Cosa? Perché? Perché ho bisogno di un rientro extra in questo caso? Non riesco a trovare nulla su questo, probabilmente perché queste parole chiave sono così brevi e comuni nel linguaggio quotidiano. C'è qualche specifica che spiega questo comportamento?

+1

Il livello di indentazione del blocco 'let' inizia dal primo carattere non di spazi bianchi dopo' let'.Quindi 'True' viene interpretato come clausola nel blocco' let'; un altro spazio ti porterà all'interno del blocco 'case' – luqui

risposta

7

Non ho la dicitura esatta dalla specifica, ma questo Wikibook page spiega il problema in modo abbastanza chiaro.

Il motivo per cui funziona così è semplice: per supportare le variabili più vincolanti tramite un singolo let-gruppo, come ad esempio:

c = do 
    let c' = … 
     d = … 
     e = … 
    return c' 

tuo True -> … e False -> … vengono erroneamente interpretati come variabili aggiuntive ad essere vincolati.

+0

E qui ho pensato che la capitalizzazione dei costruttori di dati fosse intesa a rimuovere ambiguità come questa. Suppongo che sia quello che ottengo cercando di lavorare con Python e altri linguaggi allo stesso tempo. – user2085282

+2

"La capitalizzazione dei costruttori di dati aveva lo scopo di rimuovere ambiguità come questa" Non puoi fare affidamento su questo in questo caso. Cosa succede se hai una corrispondenza di modello come: 'caso ... di {x -> ...; _ -> ...; } '? In questo caso, 'x' e' _' sono entrambi nomi di variabili valide. (Esempio conciato, lo so, ma ancora.) – Rufflewind

+4

E anche l'altro modo, "Let Just f = ..." è una dichiarazione perfettamente valida. –

7

Le regole di rientro di base sono in realtà abbastanza semplice:

  • dopo le parole chiave che iniziano un blocco (where, let, do, case .. of) annotare la colonna in cui inizia la parola successiva (che potrebbe essere in riga successiva)
  • righe rientrate esattamente come che sono nuove voci nel blocco
  • linee rientrate più che continuano la voce precedente
  • un indente linea d inferiore che termina il blocco a destra prima linea
  • in blocchi nidificati, applicare le regole al blocco più esterno, prima

esempio Tricky:

1 + case x of 
     A -> 45 -- note where "A" starts 
     B -> 10 -- same indentation: another case branch 
     + 2  -- more indented, so it's "10+2" 
    + 10  -- less indented, so it's "1+(case ...)+10" 

Nel suo caso,

let b' = case True of 
    True -> True 
    False -> False 

abbiamo due blocchi nidificati, uno per let e uno per case..of. I blocchi let utilizzano la colonna di b'. Il blocco case..of tenta di riutilizzare la stessa colonna, ma per prima cosa è necessario applicare le regole al blocco più esterno. Quindi la riga True -> ... è in realtà una nuova voce del blocco let. Questo innesca un errore di analisi.

Problemi correlati