2011-10-26 25 views
5

Tengo una pregunta rápida. Haskell me lanza el 57 - Undefined variable "f" error y no tengo idea de por qué. Te agradecería que pudieras echar un vistazo a esto.Variable indefinida, Haskell

Código:

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 

Definición de tipo:

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

Honestamente, no sé la respuesta, pero pensé que el bloque de dónde tenía que venir después de la declaración. En otras palabras, ¿has intentado mover el bloque completo donde una línea arriba? – Ramy

Respuesta

9

El bloque donde se aplica sólo al caso directamente ante ella, no todos los casos de la función eval'. Entonces, f se define (pero no se usa) en eval' (Id id) = 5, pero no está en el alcance en la línea 57. Para solucionar esto, debe mover el bloque where directamente después de la línea 57.

+0

O simplemente ponga "f = ..." justo después de la última línea "eval" - teniendo un bloque where anidado dentro de otro donde el bloqueo me parece extraño, aunque tal vez haya buenas razones para ello en algunos casos. – MatrixFrog

+0

@MatrixFrog: Sí, a veces hay muy buenas razones para anidar 'where's; si aplica manualmente una 'transformación de argumento estático', por ejemplo. Aquí, el 'where' anidado se usa para crear un nombre corto para algo usando un valor vinculado en el patrón, que también es un uso común. –

3

Exactamente lo que sepp2k dijo. En este caso, prefiero simplemente cambiar las líneas 57 y 58, por lo que el where se adjunta a la ecuación correcta sin dividir las ecuaciones para eval', que es más legible.

O no utilice f en absoluto, que sea

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

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

Moviéndose getFunctionOrApp (y getIdVal) al mismo nivel where como eval', que incluso puede ser razonable para definirlos en el nivel superior.

Cuestiones relacionadas