2013-08-01 2 views
3

У меня есть программа, которая пересекает AST и возвращает карту используемых функций и переменных и сколько раз они возникали. Вот оно:Haskell: Исправить неустранимые шаблоны в функции

import Data.Map 
import Language.Haskell.Exts.Syntax 

increment :: Ord a => a -> Map a Int -> Map a Int 
increment a = insertWith (+) a 1 

fromName :: Name -> String 
fromName (Ident s) = s 
fromName (Symbol st) = st 

fromQName :: QName -> String 
fromQName (Qual _ fn) = fromName fn 
fromQName (UnQual n) = fromName n 

fromLiteral :: Literal -> String 
fromLiteral (Int int) = show int 

fromQOp :: QOp -> Map String Int 
fromQOp (QVarOp qn) = increment (fromQName qn) empty 

fromExp :: Exp -> String 
fromExp (Var qn) = fromQName qn 
fromExp (Paren e1) = "()" 

vars :: Exp -> Map String Int 
vars (Var qn) = increment (fromQName qn) empty 
vars (Lit l) = increment (fromLiteral l) empty 
vars (Paren e1) = increment "()" (vars e1) 
vars (InfixApp exp1 qop exp2) = increment (fromExp exp1) $ unionWith (+) (fromQOp qop) (vars exp2) 

t3 = (InfixApp (Var (UnQual (Ident "x"))) (QVarOp (UnQual (Symbol "+"))) (Paren (InfixApp (Lit (Int 3)) (QVarOp (UnQual (Symbol "+"))) (Lit (Int 2))))) 

Программа работает и работает даже в большинстве случаев, но когда я называю «ВАР» на AST с «Paren» (как t3), я получаю следующее сообщение об ошибке:

fromList *** Exception: parsemap.hs:(22,1)-(23,25): Non-exhaustive patterns in function fromExp 

Я не уверен, как это исправить, и я мог бы использовать некоторую помощь. Кстати, конструкторы, которые я использую, можно найти в http://hackage.haskell.org/packages/archive/haskell-src-exts/1.0.1/doc/html/Language-Haskell-Exts-Syntax.html#t:Exp в случае, если это помогает.

Заранее благодарен!

+4

Попробуйте скомпилировать свои программы с помощью '-Wall', чтобы получить предупреждение о неисчерпаемых шаблонах. – jberryman

ответ

5

Ну, если вы посмотрите на это definition of Exp, вы увидите, что есть целая куча возможных конструкторов. Но в вашей функции вы проверяете только два из них.

Так что произойдет, если я позвоню fromExp (Lit l)? Это не определено, что плохо. Самый простой способ исправить это, чтобы добавить в еще одном случае, который охватывает все другие возможные конструктор:

fromExp :: Exp -> String 
fromExp (Var qn) = fromQName qn 
fromExp (Paren e1) = "()" 
fromExp _   = "Not defined yet" 

Таким образом, если вы звоните fromExp с любым другим конструктором, он будет возвращать "Not defined yet".


В данном конкретном случае, оценка:

vars t3 
=> vars (InfixApp (Var (UnQual (Ident "x"))) (QVarOp (UnQual (Symbol "+"))) (Paren (InfixApp (Lit (Int 3)) (QVarOp (UnQual (Symbol "+"))) (Lit (Int 2))))) 
=> vars (Paren (InfixApp (Lit (Int 3)) (QVarOp (UnQual (Symbol "+"))) (Lit (Int 2))))) 
=> vars (InfixApp (Lit (Int 3)) (QVarOp (UnQual (Symbol "+"))) (Lit (Int 2)))) 
=> fromExp (Lit (Int 3)) 

и нет fromExp (Lit l) определения, чтобы оценить это выражение.

+1

Я заработал. Большое спасибо за Вашу помощь! Теперь я начну добавлять определения для конструкторов, как вы предложили. – user2548080

Смежные вопросы