2009-07-21 7 views
9

Ho una domanda molto semplice. Mi piacerebbe usare una clausola where dopo un blocco di codice che utilizza gli operatori di bind ma ottengo un errore di compilazione.Haskell: Posso usare una clausola where dopo un blocco con operatori di binding (>> =)?

Ecco un semplice esempio:

main = 
    putStrLn "where clause test:" >> 
    return [1..10] >>= \list -> 
    print list' 
     where list' = reverse list -- test1.hs:5:28: Not in scope: `list' 

posso usare una clausola let per la lista' come in

main = 
    putStrLn "where clause test:" >> 
    return [1..10] >>= \list -> 
    let list' = reverse list -- works of course 
    in print list' 

ma mi piacerebbe molto se ho potuto utilizzare una clausola dove. ..

ho provato anche con la notazione fare

main = do 
    putStrLn "where clause test:" 
    list <- return [1..10] 
    print list' 
     where list' = reverse list --test3.hs:5:30: Not in scope: `list' 

Stesso problema. Posso usare una clausola where in queste circostanze?

risposta

10

Come spiega l'odioso, non è possibile utilizzare le clausole where come si fa.

L'errore si verifica perché in questo codice:

main = 
    return [1..10] >>= \list -> 
    print list' 
    where 
     list' = reverse list 

La where -clause è attaccato alla funzione principale.

Ecco la stessa funzione con più parentesi:

main = return [1..10] >>= (\list -> print list') 
    where 
    list' = reverse list 

Credo che la sua abbastanza ovvio il motivo per cui si ottiene la "out of scope" Errore: l'associazione per list è profondo all'interno del main espressione, non qualcosa che la clausola di where può raggiungere.

Quello che faccio di solito in questa situazione (e sono stato morso dalla stessa cosa un sacco di volte). Introduco semplicemente una funzione e passo lo list come argomento.

main = do 
    list <- return [1..10] 
    let list' = f list 
    print list' 
    where 
    f list = reverse list -- Consider renaming list, 
          -- or writing in point-free style 

Naturalmente, immagino il codice vero e proprio nella funzione f è molto più che appena reverse ed è per questo che si desidera all'interno di una clausola di where, invece di un inline let vincolante. Se il codice all'interno della funzione f è molto piccolo, lo scriverei semplicemente nell'associazione let e non passerei attraverso l'overhead dell'introduzione di una nuova funzione.

+0

Grazie, il tuo esempio con più parentesi lo cancella per me. –

1

Per quanto posso dire, la clausola where viene utilizzata solo nelle associazioni . La parte interna di un'istruzione vincolante >> (=) non è un binding locale (due diversi tipi di binding in quella frase).

paragonabile a questo:

main = f [1..10] 

f list = 
    putStrLn "where clause test:" >> print list' 
     where list' = reverse list 

si potrebbe desiderare di fare riferimento al Haskell 98 syntax report - non so quanto aiuto che sarebbe stato.

Se sbaglio, qualcuno mi correggerà sicuramente, ma sono abbastanza sicuro che non puoi usare una clausola where nello stile che hai mostrato sopra. list non sarà mai incluso in una clausola where, a meno che non sia un parametro della funzione.

+0

Un'astrazione lambda è un'espressione, non una dichiarazione o una rilegatura, sebbene possa legare nuovi nomi ... – ephemient

+0

Whoa, chi ha fatto questo? Penso che sia corretto, se non così completo come potrebbe essere. – ephemient

+0

non è rilevante. l'OP vuole usare "lista", un risultato di una serie di calcoli monadici; non un valore che è al di fuori della monade – newacct

11

Il problema è che let-in è espressione, che può essere usato all'interno di altre espressioni, mentre where può essere utilizzato solo su un (modulo | classe | esempio | GADT | ...) dichiarazione o una (funzione | modello) vincolante.

Dal rapporto Haskell 98 su declarations and bindings,

p | g1=e1
    | g2=e2
    …
    | gm=em
  where {decls}

è lo zucchero per

p= letdeclsin
      ifg1thene1else
      ifg2thene2else
      …
      ifgmthenemelse error "Unmatched pattern"

o, semplificando le cose rimuovendo guardie,

p=ewhere {decls}

è zucchero per

in entrambi i collegamenti funzione e modello. Questo è vero anche se il tuo e è un do { & hellip; } costrutto.

Se si vuole avere un locale, il legame con un particolare sottoespressione all'interno di un'espressione più grande, è necessario utilizzare let-in (o semplicemente let all'interno di un do, ma questo è solo zucchero per let-in).

Non si può nemmeno scrivere

main = do 
    putStrLn "where clause test: " 
    list <- return [1..10] 
    (print list' where list' = reverse list) 

perché "ewhere {decls}" non è un'espressione giuridica – where può essere utilizzato solo nelle dichiarazioni e attacchi.

main = do 
    putStrLn "where clause test: " 
    list <- return [1..10] 
    let list' = list'' where list'' = reverse list 
    print list' 

Questo è legale (se un po 'forzato).

+0

perché non solo "lascia lista" = lista inversa "? Nell'ultimo esempio? – newacct

+0

Grazie, dovrei fare riferimento più spesso alla relazione Haskell quando ho domande fondamentali sulla lingua come questa. –

+0

@newacct: la domanda dell'OP include già questa variante, che ovviamente funziona. – ephemient

Problemi correlati