5

I've got a quick question. Haskell is throwing the 57 - Undefined variable "f" error at me and I've no idea why. I'd appreciate it if you could have a look at this.

Code:

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

Type definition:

data Expr = Num Float | Id String | App String [ Expr ]
           deriving (Eq, Ord, Show)
type Environment = [ ( String, Float ) ]
1
  • 3
    i honestly don't know the answer but I thought that the where block had to come after the statment. In other words, have you tried moving the whole where block up one line? Commented Oct 26, 2011 at 16:47

2 Answers 2

9

The where block applies only to the case directly before it, not to all cases of the eval' function. So f is defined (but not used) in eval' (Id id) = 5, but it's not in scope in line 57. To fix this you need to move the where block directly after line 57.

Sign up to request clarification or add additional context in comments.

2 Comments

Or just put "f = ..." right after the last "eval'" line -- having a where block nested inside another where block seems strange to me, though perhaps there are good reasons for it in some cases.
@MatrixFrog: Yes, there are sometimes very good reasons to nest wheres; if you manually apply a 'static argument transformation', for example. Here, the nested where is used to create a short name for something using a value bound in the pattern, which is also a common use.
3

Exactly what sepp2k said. In this case, though, I'd prefer simply swapping lines 57 and 58, so the where is attached to the right equation without splitting the equations for eval', that's more readable.

Or don't use f at all, make it

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

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

Moving getFunctionOrApp (and getIdVal) to the same-level where as eval', it may even be reasonable to define them at the top level.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.