2011-10-26 9 views
5

Ho una domanda veloce. Haskell sta lanciando il 57 - Undefined variable "f" error e non ho idea del perché. Lo apprezzerei se potessi dare un'occhiata a questo.Variabile indefinita, Haskell

Codice:

eval :: Expr -> Environment -> Float 
eval expr env = eval' expr 
    where 
    eval' :: Expr-> Float 
    eval' (Num num) = num 
    eval' (App app exprs) = foldl1 (f) (map eval' exprs) -- **Line 57** 
    eval' (Id id) = 5 
     where 
     f = getFunctionForApp app     -- **f is here** 
     getFunctionForApp :: String -> (Float->Float->Float) 
     getFunctionForApp "+" = (+) 
     getFunctionForApp "-" = (-) 
     getFunctionForApp "*" = (*) 
     getFunctionForApp "/" = (/) 
     getIdVal :: String -> Environment -> Float 
     getIdVal id ((curId, val):envrs) 
      |curId == id = val 
      | otherwise = getIdVal id envrs 

Tipo definizione:

data Expr = Num Float | Id String | App String [ Expr ] 
      deriving (Eq, Ord, Show) 
type Environment = [ (String, Float) ] 
+3

sinceramente non conosco la risposta, ma ho pensato che il blocco dov'era dovuto arrivare dopo la dichiarazione. In altre parole, hai provato a spostare l'intero punto in cui bloccare una riga? – Ramy

risposta

9

Il blocco in cui si applica solo al caso direttamente davanti, non a tutti i casi della funzione eval'. Quindi f è definito (ma non utilizzato) in eval' (Id id) = 5, ma non è nella portata 57. Per risolvere questo è necessario spostare il blocco dove direttamente dopo la linea 57.

+0

Oppure metti "f = ..." subito dopo l'ultima riga "eval" - con un blocco dove nidificato dentro un altro dove il blocco mi sembra strano, anche se forse ci sono buone ragioni per farlo in alcuni casi. – MatrixFrog

+0

@MatrixFrog: Sì, a volte ci sono ottimi motivi per nidificare 'where's; se si applica manualmente una "trasformazione argomento statica", ad esempio. Qui, il nidificato 'where' è usato per creare un nome breve per qualcosa che usa un valore associato nel modello, che è anche un uso comune. –

3

Esattamente quello che ha detto sepp2k. In questo caso, tuttavia, preferirei semplicemente scambiare le righe 57 e 58, quindi lo where è collegato all'equazione destra senza dividere le equazioni per eval', che è più leggibile.

oppure non utilizzare f a tutti, rendere

eval' (App app exprs) = foldl1 (getFunctionOrApp app) (map eval' exprs) 
eval' (Id id) = 5 

getFunctionOrApp :: String -> (Float -> Float -> Float) 
getFunctionOrApp "+" = ... 

Moving getFunctionOrApp (e getIdVal) allo stesso livello come whereeval', può anche essere ragionevole definirli al livello superiore.

Problemi correlati