2015-03-23 40 views
5

ho scritto il seguente pezzo di codice:Strano comportamento in GHCi

it :: Int -> Int 
it n 
    | n < 1  = error "Invalid entry." 
    | n == 1 = 0 
    | otherwise = 1 + it (n `quot` 2) 

Quando carico in GHCi, qualcosa di strano accade. La prima volta che chiamo la funzione it, funziona correttamente e restituisce i risultati previsti. Tuttavia, la prossima volta, ottengo il seguente incidente:

λ: :t it 
it :: Int -> Int 
λ: it 2 
1 
λ: it 2 

<interactive>:4:1: 
    Couldn't match expected type `a0 -> t0' with actual type `Int' 
    The function `it' is applied to one argument, 
    but its type `Int' has none 
    In the expression: it 2 
    In an equation for `it': it = it 2 
λ: :t it 
it :: Int 
λ: it 
1 

Sembra che il tipo di it viene in qualche modo modificato dopo la prima chiamata. Le cose si fanno ancora più strano quando it viene chiamato più volte da main, vale a dire tutte le chiamate restituire i risultati attesi, ma alla fine () è assegnato come tipo di it:

main :: IO() 
main = do 
    let r1 = it 1 
     r2 = it 2 
     r3 = it 3 
    print r1 
    print r2 
    print r3 

λ: main 
0 
1 
1 
λ: :t it 
it ::() 

Credo che questo sia un bug relativo alla l'identificatore it e le parti interne di GHCi, poiché la rinomina della funzione in qualcos'altro (come it') risolve completamente il problema. Oltre a ciò, il corpo della funzione sembra non avere alcuna influenza; fare let it = (+) 2 e valutarlo più volte è anche problematico.

Qualsiasi intuizione sarebbe apprezzata. L'output di ghci --version è "versione 7.6.3".

risposta

11

La sfortuna nella denominazione: it è il nome che GHCi associa automaticamente al risultato della valutazione precedente, in modo da poterlo consultare nuovamente. Quindi il tuo primo utilizzo lo riavvolge immediatamente, ombreggia la tua definizione.

Se it è definito in un modulo, si dovrebbe comunque essere in grado di fare riferimento ad esso in modo affidabile da GHCi con il prefisso del modulo, ad es. Main.it.

+0

Grazie per la risposta! Sono contento di sapere che questa è solo un'altra istanza del dilemma "bug vs feature". :-) Vedo certamente l'utilità di 'it', ma mi chiedo se ci sia un modo migliore per implementare questa funzione in GHCi per evitare tale confusione ... Forse usando una parola chiave speciale, piuttosto che una funzione Haskell valida identificatore? O almeno avvisare l'utente durante il caricamento di funzioni chiamate con nomi GHCi riservati ... Infine, ci sono altri nomi speciali in GHCi di cui dovrei essere a conoscenza? –

+1

@alexandrelucchesi Ricordo da lungo tempo che gli Hug usavano invece '$$', anche se ciò poteva essere confuso con un operatore. Penso che GHCi usi un identificatore ordinario perché la funzione è implementata come codice normale, vedi [il manuale] (https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/interactive-evaluation.html#idp7106400). Non sono a conoscenza di altri nomi speciali, ': show bindings' non elenca più. –