未定义变量,Haskell

5

我有一个快速的问题。Haskell 给我抛出了一个 57 - 未定义变量 "f" 错误,但我不知道为什么会出现这个错误。如果你能看一下这个问题,我会很感激。

代码:

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

类型定义:

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

3
我不知道答案,但我认为where语句块必须放在语句之后。换句话说,你试过把整个where语句块上移一行吗? - Ramy
2个回答

9
where块仅适用于直接在其之前的情况,而不是eval'函数的所有情况。因此,在eval'(Id id)= 5中定义了f(但未使用),但其在第57行不在作用域内。要解决此问题,您需要将where块直接移动到57行之后。

或者将"f = ..."放在最后一个"eval'"行的后面 - 将一个where块嵌套在另一个where块中似乎对我来说有些奇怪,但也许在某些情况下有一些合理的原因。 - Tyler
@MatrixFrog:是的,有时候嵌套“where”语句是非常必要的,比如手动应用“静态参数转换”。在这里,嵌套的“where”语句用于使用模式中绑定的值创建某个东西的简短名称,这也是一个常见的用法。 - Daniel Fischer

3

就像sepp2k所说的那样。在这种情况下,我更喜欢简单地交换57和58行,这样where就附加到正确的方程式上,而不会分裂eval'的方程式,这样更易读。

或者根本不使用f,使它成为

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

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

getFunctionOrApp(和getIdVal)移动到与eval'相同级别的where中,甚至可以在顶层定义它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接