如何解决处理计算器程序中的令牌错误
我正在尝试处理我用haskell制作的计算器程序中的令牌错误,我的代码如下:
import Data.Char
import Control.Applicative
data MayError a = Value a | Error String
instance (Show a) => Show (MayError a) where
show (Value x) = show x
show (Error s) = "error: " ++ s
instance Functor MayError where
fmap f (Value x) = Value (f x)
fmap f (Error s) = Error s
instance Applicative MayError where
pure x = Value x
(Value f) <*> (Value x) = Value (f x)
(Value f) <*> (Error s) = Error s
(Error s) <*> _ = Error s
instance Monad MayError where
return x = Value x
(Value x) >>= f = f x
(Error s) >>= f = Error s
{- tokenizer -}
data Token = Num Int | Add | Sub | Mul | Div | Exp | LPar | RPar deriving (Eq,Show)
tokens :: String -> MayError [Token]
tokens [] = []
tokens ('+':cs) = Add:(tokens cs)
tokens ('-':cs) = Sub:(tokens cs)
tokens ('*':cs) = Mul:(tokens cs)
tokens ('/':cs) = Div:(tokens cs)
tokens ('(':cs) = LPar:(tokens cs)
tokens (')':cs) = RPar:(tokens cs)
tokens ('^':cs) = Exp:(tokens cs)
tokens (c:cs) | isDigit c = let (ds,rs) = span isDigit (c:cs)
in Num(read ds):(tokens rs)
| isSpace c = tokens cs
| otherwise = Error "unknown token"
{- parser -}
data ParseTree = Number Int |
Plus ParseTree ParseTree |
Minus ParseTree ParseTree |
Times ParseTree ParseTree |
Divide ParseTree ParseTree |
Power ParseTree ParseTree
deriving Show
type Parser = [Token] -> MayError(ParseTree,[Token])
parseFactor::Parser
parseFactor (Num x:l) = return (Number x,l)
parseFactor (Add:l) = parseFactor l
parseFactor (Sub:l) = let (p1,l1) = parseFactor l in (Minus (Number 0) p1,l1)
parseFactor (LPar:l) = let (p1,RPar:l1) = parseExpr l in (p1,l1)
parseFactor _ = Error "parse error"
parseExponent::Parser
parseExponent l = nextExp $ parseFactor l
where nextExp(p1,Exp:l1) = let (p2,l2) = parseFactor l1
in nextExp(Power p1 p2,l2)
nextExp x = x
parseTerm::Parser
parseTerm l = nextFactor $ parseExponent l
where nextFactor(p1,Mul:l1) = let (p2,l2) = parseExponent l1
in nextFactor(Times p1 p2,l2)
nextFactor(p1,Div:l1) = let (p2,l2) = parseExponent l1
in nextFactor(Divide p1 p2,l2)
nextFactor x = x
parseExpr::Parser
parseExpr l = nextTerm $ parseTerm l
where nextTerm(p1,Add:l1) = let (p2,l2) = parseTerm l1
in nextTerm(Plus p1 p2,l2)
nextTerm(p1,Sub:l1) = let (p2,l2) = parseTerm l1
in nextTerm(Minus p1 p2,l2)
nextTerm x = x
{- evaluator -}
eval::ParseTree -> MayError Int
eval (Number x) = Value x
eval (Plus p1 p2) = do x <- eval p1
y <- eval p2
return (x+y)
eval (Minus p1 p2) = do x <- eval p1
y <- eval p2
return (x-y)
eval (Times p1 p2) = do x <- eval p1
y <- eval p2
return (x*y)
eval (Divide p1 p2) = do x <- eval p1
y <- eval p2
if y == 0 then Error "division by 0"
else return (x `div` y)
eval (Power p1 p2) = do x <- eval p1
y <- eval p2
if y < 0 then Error "cannot process negative exponents"
else return (x^y)
parse :: [Token] -> MayError ParseTree
parse ts = do (pt,rs) <- parseExpr ts
if null rs then return pt else Error "extra token"
{- main -}
main = do cs <- getContents
putStr $ unlines $ map show $
map (\s -> tokens s >>= parse >>= eval) $ lines cs
当我不尝试解析错误时一切正常,但现在错误如下所示:
calc_final2.hs:29:13: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[a1]’
• In the expression: []
In an equation for ‘tokens’: tokens [] = []
|
29 | tokens [] = []
| ^^
calc_final2.hs:30:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: Add : (tokens cs)
In an equation for ‘tokens’: tokens ('+' : cs) = Add : (tokens cs)
|
30 | tokens ('+':cs) = Add:(tokens cs)
| ^^^^^^^^^^^^^^^
calc_final2.hs:30:24: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: Add : (tokens cs)
In an equation for ‘tokens’: tokens ('+' : cs) = Add : (tokens cs)
|
30 | tokens ('+':cs) = Add:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:31:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: Sub : (tokens cs)
In an equation for ‘tokens’: tokens ('-' : cs) = Sub : (tokens cs)
|
31 | tokens ('-':cs) = Sub:(tokens cs)
| ^^^^^^^^^^^^^^^
calc_final2.hs:31:24: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: Sub : (tokens cs)
In an equation for ‘tokens’: tokens ('-' : cs) = Sub : (tokens cs)
|
31 | tokens ('-':cs) = Sub:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:32:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: Mul : (tokens cs)
In an equation for ‘tokens’: tokens ('*' : cs) = Mul : (tokens cs)
|
32 | tokens ('*':cs) = Mul:(tokens cs)
| ^^^^^^^^^^^^^^^
calc_final2.hs:32:24: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: Mul : (tokens cs)
In an equation for ‘tokens’: tokens ('*' : cs) = Mul : (tokens cs)
|
32 | tokens ('*':cs) = Mul:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:33:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: Div : (tokens cs)
In an equation for ‘tokens’: tokens ('/' : cs) = Div : (tokens cs)
|
33 | tokens ('/':cs) = Div:(tokens cs)
| ^^^^^^^^^^^^^^^
calc_final2.hs:33:24: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: Div : (tokens cs)
In an equation for ‘tokens’: tokens ('/' : cs) = Div : (tokens cs)
|
33 | tokens ('/':cs) = Div:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:34:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: LPar : (tokens cs)
In an equation for ‘tokens’: tokens ('(' : cs) = LPar : (tokens cs)
|
34 | tokens ('(':cs) = LPar:(tokens cs)
| ^^^^^^^^^^^^^^^^
calc_final2.hs:34:25: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: LPar : (tokens cs)
In an equation for ‘tokens’: tokens ('(' : cs) = LPar : (tokens cs)
|
34 | tokens ('(':cs) = LPar:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:35:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: RPar : (tokens cs)
In an equation for ‘tokens’: tokens (')' : cs) = RPar : (tokens cs)
|
35 | tokens (')':cs) = RPar:(tokens cs)
| ^^^^^^^^^^^^^^^^
calc_final2.hs:35:25: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: RPar : (tokens cs)
In an equation for ‘tokens’: tokens (')' : cs) = RPar : (tokens cs)
|
35 | tokens (')':cs) = RPar:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:36:19: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: Exp : (tokens cs)
In an equation for ‘tokens’: tokens ('^' : cs) = Exp : (tokens cs)
|
36 | tokens ('^':cs) = Exp:(tokens cs)
| ^^^^^^^^^^^^^^^
calc_final2.hs:36:24: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens cs)’
In the expression: Exp : (tokens cs)
In an equation for ‘tokens’: tokens ('^' : cs) = Exp : (tokens cs)
|
36 | tokens ('^':cs) = Exp:(tokens cs)
| ^^^^^^^^^
calc_final2.hs:38:32: error:
• Couldn't match expected type ‘MayError [Token]’
with actual type ‘[Token]’
• In the expression: Num (read ds) : (tokens rs)
In the expression:
let (ds,rs) = span isDigit (c : cs) in Num (read ds) : (tokens rs)
In an equation for ‘tokens’:
tokens (c : cs)
| isDigit c
= let (ds,rs) = span isDigit (c : cs)
in Num (read ds) : (tokens rs)
| isSpace c = tokens cs
| otherwise = Error "unknown token"
|
38 | in Num(read ds):(tokens rs)
| ^^^^^^^^^^^^^^^^^^^^^^^^
calc_final2.hs:38:46: error:
• Couldn't match expected type ‘[Token]’
with actual type ‘MayError [Token]’
• In the second argument of ‘(:)’,namely ‘(tokens rs)’
In the expression: Num (read ds) : (tokens rs)
In the expression:
let (ds,rs) = span isDigit (c : cs) in Num (read ds) : (tokens rs)
|
38 | in Num(read ds):(tokens rs)
| ^^^^^^^^^
calc_final2.hs:56:38: error:
• Couldn't match expected type ‘(a,b)’
with actual type ‘MayError (ParseTree,[Token])’
• In the expression: parseFactor l
In a pattern binding: (p1,l1) = parseFactor l
In the expression:
let (p1,l1)
• Relevant bindings include
p1 :: a (bound at calc_final2.hs:56:28)
l1 :: b (bound at calc_final2.hs:56:32)
|
56 | parseFactor (Sub:l) = let (p1,l1)
| ^^^^^^^^^^^^^
calc_final2.hs:56:55: error:
• Couldn't match expected type ‘MayError (ParseTree,[Token])’
with actual type ‘(ParseTree,b0)’
• In the expression: (Minus (Number 0) p1,l1)
In the expression:
let (p1,l1)
In an equation for ‘parseFactor’:
parseFactor (Sub : l)
= let (p1,l1)
|
56 | parseFactor (Sub:l) = let (p1,l1)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
calc_final2.hs:57:44: error:
• Couldn't match expected type ‘(a,[Token])’
with actual type ‘MayError (ParseTree,[Token])’
• In the expression: parseExpr l
In a pattern binding: (p1,RPar : l1) = parseExpr l
In the expression: let (p1,RPar : l1) = parseExpr l in (p1,l1)
• Relevant bindings include p1 :: a (bound at calc_final2.hs:57:29)
|
57 | parseFactor (LPar:l) = let (p1,l1)
| ^^^^^^^^^^^
calc_final2.hs:57:59: error:
• Couldn't match expected type ‘MayError (ParseTree,[Token])’
with actual type ‘(a0,[Token])’
• In the expression: (p1,l1)
In the expression: let (p1,l1)
In an equation for ‘parseFactor’:
parseFactor (LPar : l)
= let (p1,l1)
|
57 | parseFactor (LPar:l) = let (p1,l1)
| ^^^^^^^^
calc_final2.hs:61:19: error:
• Couldn't match expected type ‘MayError (ParseTree,[Token])’
• In the expression: nextExp $ parseFactor l
In an equation for ‘parseExponent’:
parseExponent l
= nextExp $ parseFactor l
where
nextExp (p1,Exp : l1) = let ... in nextExp (Power p1 p2,l2)
nextExp x = x
|
61 | parseExponent l = nextExp $ parseFactor l
| ^^^^^^^^^^^^^^^^^^^^^^^
calc_final2.hs:61:29: error:
• Couldn't match expected type ‘(ParseTree,[Token])’
• In the second argument of ‘($)’,namely ‘parseFactor l’
In the expression: nextExp $ parseFactor l
In an equation for ‘parseExponent’:
parseExponent l
= nextExp $ parseFactor l
where
nextExp (p1,l2)
nextExp x = x
|
61 | parseExponent l = nextExp $ parseFactor l
| ^^^^^^^^^^^^^
calc_final2.hs:62:46: error:
• Couldn't match expected type ‘(a,[Token])’
• In the expression: parseFactor l1
In a pattern binding: (p2,l2) = parseFactor l1
In the expression:
let (p2,l2) = parseFactor l1 in nextExp (Power p1 p2,l2)
• Relevant bindings include
p2 :: a (bound at calc_final2.hs:62:36)
l2 :: b (bound at calc_final2.hs:62:40)
|
62 | where nextExp(p1,l2) = parseFactor l1
| ^^^^^^^^^^^^^^
calc_final2.hs:67:15: error:
• Couldn't match expected type ‘MayError (ParseTree,[Token])’
• In the expression: nextFactor $ parseExponent l
In an equation for ‘parseTerm’:
parseTerm l
= nextFactor $ parseExponent l
where
nextFactor (p1,Mul : l1) = let ... in nextFactor (Times p1 p2,l2)
nextFactor (p1,Div : l1)
= let ... in nextFactor (Divide p1 p2,l2)
nextFactor x = x
|
67 | parseTerm l = nextFactor $ parseExponent l
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
calc_final2.hs:67:28: error:
• Couldn't match expected type ‘(ParseTree,namely ‘parseExponent l’
In the expression: nextFactor $ parseExponent l
In an equation for ‘parseTerm’:
parseTerm l
= nextFactor $ parseExponent l
where
nextFactor (p1,l2)
nextFactor x = x
|
67 | parseTerm l = nextFactor $ parseExponent l
| ^^^^^^^^^^^^^^^
calc_final2.hs:68:48: error:
• Couldn't match expected type ‘(a,[Token])’
• In the expression: parseExponent l1
In a pattern binding: (p2,l2) = parseExponent l1
In the expression:
let (p2,l2) = parseExponent l1 in nextFactor (Times p1 p2,l2)
• Relevant bindings include
p2 :: a (bound at calc_final2.hs:68:39)
l2 :: b (bound at calc_final2.hs:68:42)
|
68 | where nextFactor(p1,l2) = parseExponent l1
| ^^^^^^^^^^^^^^^^
calc_final2.hs:70:48: error:
• Couldn't match expected type ‘(a,l2) = parseExponent l1 in nextFactor (Divide p1 p2,l2)
• Relevant bindings include
p2 :: a (bound at calc_final2.hs:70:39)
l2 :: b (bound at calc_final2.hs:70:42)
|
70 | nextFactor(p1,l2) = parseExponent l1
| ^^^^^^^^^^^^^^^^
calc_final2.hs:75:15: error:
• Couldn't match expected type ‘MayError (ParseTree,[Token])’
• In the expression: nextTerm $ parseTerm l
In an equation for ‘parseExpr’:
parseExpr l
= nextTerm $ parseTerm l
where
nextTerm (p1,Add : l1) = let ... in nextTerm (Plus p1 p2,l2)
nextTerm (p1,Sub : l1) = let ... in nextTerm (Minus p1 p2,l2)
nextTerm x = x
|
75 | parseExpr l = nextTerm $ parseTerm l
| ^^^^^^^^^^^^^^^^^^^^^^
calc_final2.hs:75:26: error:
• Couldn't match expected type ‘(ParseTree,namely ‘parseTerm l’
In the expression: nextTerm $ parseTerm l
In an equation for ‘parseExpr’:
parseExpr l
= nextTerm $ parseTerm l
where
nextTerm (p1,l2)
nextTerm x = x
|
75 | parseExpr l = nextTerm $ parseTerm l
| ^^^^^^^^^^^
calc_final2.hs:76:46: error:
• Couldn't match expected type ‘(a,[Token])’
• In the expression: parseTerm l1
In a pattern binding: (p2,l2) = parseTerm l1
In the expression:
let (p2,l2) = parseTerm l1 in nextTerm (Plus p1 p2,l2)
• Relevant bindings include
p2 :: a (bound at calc_final2.hs:76:37)
l2 :: b (bound at calc_final2.hs:76:40)
|
76 | where nextTerm(p1,l2) = parseTerm l1
| ^^^^^^^^^^^^
calc_final2.hs:78:46: error:
• Couldn't match expected type ‘(a,l2) = parseTerm l1 in nextTerm (Minus p1 p2,l2)
• Relevant bindings include
p2 :: a (bound at calc_final2.hs:78:37)
l2 :: b (bound at calc_final2.hs:78:40)
|
78 | nextTerm(p1,l2) = parseTerm l1
| ^^^^^^^^^^^^
我真正想做的是在输入一些无效令牌时让我的程序显示“未知令牌”。
解决方法
由于tokens
的返回类型是MayError [Token]
,所以需要将项目包裹在Value
中,对于我们递归的项目,我们可以执行一个fmap
来附加到包含在 Value
中的列表:
tokens :: String -> MayError [Token]
tokens [] = Value []
tokens ('+':cs) = (Add:) <$> tokens cs
tokens ('-':cs) = (Sub:) <$> tokens cs
tokens ('*':cs) = (Mul:) <$> tokens cs
tokens ('/':cs) = (Div:) <$> tokens cs
tokens ('(':cs) = (LPar:) <$> tokens cs
tokens (')':cs) = (RPar:) <$> tokens cs
tokens ('^':cs) = (Exp:) <$> tokens cs
tokens (c:cs) | isDigit c = let (ds,rs) = span isDigit (c:cs)
in (Num (read ds):) <$> tokens rs
| isSpace c = tokens cs
| otherwise = Error "unknown token"
其他函数也有同样的问题:您应该将值包装在 Value
数据构造函数中,或者如果您正在处理 MayError
值,则将它们解开包装。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。