2011-10-26 17 views
5

私は簡単な質問があります。ハスケルが私に57 - Undefined variable "f" errorを投げているのですが、私はなぜそれが分かりませんか?もしあなたがこれを見ることができれば、私はそれを感謝します。未定義の変数、Haskell

コード:

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 

タイプの定義:ブロックのみを直接その前の場合と、ないeval'機能のすべての場合に適用される

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

私は正直に答えはわかりませんが、私はどこのブロックが文章の後に来なければならないと思いました。言い換えれば、1行上のブロック全体を動かしてみましたか? – Ramy

答えて

9

ザ・。したがって、はeval' (Id id) = 5で定義されています(使用されていません)が、57行目には範囲がありません。これを修正するには、57行目の直後にwhereブロックを移動する必要があります。

+0

または、最後の "評価"行の直後に "f = ..."を入れてください。どこにブロックが入れ子になっているのかは、ブロックが奇妙に見える場合があります。 – MatrixFrog

+0

@MatrixFrog:はい、時には 'where'sを入れ子にする理由があります。たとえば、「静的引数変換」を手動で適用するとします。ここでは、ネストされた 'where'は、パターンでバインドされた値を使用して何かの短い名前を作成するために使用されます。これは一般的な使用方法です。 –

3

sepp2kとまったく同じです。しかし、この場合は、単に57と58の行を交換するほうがいいので、eval'の方程式を分割することなく、whereが正しい方程式に付けられていると読みやすくなります。

それとも

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

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

eval'と同じレベルwheregetFunctionOrApp(およびgetIdVal)を移動させる、全くfを使用していない、それもトップレベルでそれらを定義するのが妥当かもしれません。