2011-10-26 14 views
5

Mam krótkie pytanie. Haskell rzuca we mnie 57 - Undefined variable "f" error i nie mam pojęcia dlaczego. Byłbym wdzięczny, gdybyś mógł rzucić okiem na to.Niezdefiniowana zmienna, Haskell

Kod: definicja

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 

Typ:

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

Szczerze mówiąc nie znam odpowiedzi, ale pomyślałem, że tam, gdzie blok musiał nadejść po przyjęciu. Innymi słowy, czy próbowałeś przenieść cały blok w jedną linię? – Ramy

Odpowiedz

9

WHERE blok odnosi się jedynie do przypadku bezpośrednio przed nim, a nie do wszystkich przypadków funkcji eval'. Tak więc f jest zdefiniowany (ale nieużywany) w eval' (Id id) = 5, ale nie ma go w linii 57. Aby to naprawić, musisz przenieść blok where bezpośrednio po linii 57.

+0

Lub po prostu umieść "f = ..." zaraz po ostatniej linii "eval" - o tym, gdzie blok zagnieżdżony jest w innym, gdzie blok wydaje mi się dziwny, choć być może istnieją ku temu powody. – MatrixFrog

+0

@MatrixFrog: Tak, czasami istnieją bardzo dobre powody, aby zagnieżdżać 'where's; jeśli ręcznie zastosujesz "statyczną transformację argumentów", na przykład. Tutaj zagnieżdżone 'where' służy do utworzenia krótkiej nazwy dla czegoś, używając wartości związanej we wzorcu, która jest również powszechnym zastosowaniem. –

3

Dokładnie to, co powiedział sepp2k. W tym przypadku jednak wolałbym po prostu zamienić linie 57 i 58, więc where jest podłączony do prawego równania bez dzielenia równań dla eval', który jest bardziej czytelny.

Albo nie używać f w ogóle, sprawiają, że

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

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

Moving getFunctionOrApp (i getIdVal) do tego samego poziomu where jak eval', to może nawet być rozsądne, aby określić je na najwyższym poziomie.

Powiązane problemy