/
arith.hs
99 lines (81 loc) · 2.59 KB
/
arith.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import Control.Monad (forM_)
import Control.Applicative hiding ((<|>))
import System.Environment (getArgs)
import Text.ParserCombinators.Parsec
data Term = TmTrue
| TmFalse
| TmIf Term Term Term
| TmZero
| TmSucc Term
| TmPred Term
| TmIsZero Term
| TmError
deriving Show
main :: IO()
main = do
args <- getArgs
forM_ args (\arg -> case parseArith arg of
Left err -> print err
Right term -> print $ eval term)
isNumerical :: Term -> Bool
isNumerical term = case term of
TmZero -> True
TmSucc subterm -> isNumerical subterm
TmPred subterm -> isNumerical subterm
_ -> False
eval :: Term -> Term
eval TmTrue = TmTrue
eval TmFalse = TmFalse
eval TmZero = TmZero
eval (TmIf term1 term2 term3) = evalIf (eval term1) term2 term3
eval (TmIsZero subterm) = evalIsZero $ eval subterm
eval (TmPred subterm) = evalPred $ eval subterm
eval (TmSucc subterm) = evalSucc $ eval subterm
eval _ = TmError
evalIf :: Term -> Term -> Term -> Term
evalIf TmTrue a _ = eval a
evalIf TmFalse _ b = eval b
evalIf _ _ _ = TmError
evalIsZero :: Term -> Term
evalIsZero TmZero = TmTrue
evalIsZero term
| isNumerical term = TmFalse
| otherwise = TmError
evalPred :: Term -> Term
evalPred TmZero = TmZero
evalPred (TmSucc subterm) = eval subterm
evalPred _ = TmError
evalSucc :: Term -> Term
evalSucc term
| isNumerical term = TmSucc term
| otherwise = TmError
parseArith :: String -> Either ParseError Term
parseArith input = parse arithParser "Failed to parse arithmetic expression" input
arithParser :: GenParser Char st Term
arithParser = try( ifParser )
<|> try( succParser )
<|> try( predParser )
<|> try( isZeroParser )
<|> try( trueParser )
<|> try( falseParser )
<|> zeroParser
trueParser :: GenParser Char st Term
trueParser = string "true" >> return TmTrue
falseParser :: GenParser Char st Term
falseParser = string "false" >> return TmFalse
zeroParser :: GenParser Char st Term
zeroParser = char '0' >> return TmZero
functionParser :: String -> (Term -> Term) -> GenParser Char st Term
functionParser name funcTerm =
funcTerm <$> (string name *> char '(' *> spaces *> arithParser <* spaces <* char ')')
succParser :: GenParser Char st Term
succParser = functionParser "succ" TmSucc
predParser :: GenParser Char st Term
predParser = functionParser "pred" TmPred
isZeroParser :: GenParser Char st Term
isZeroParser = functionParser "iszero" TmIsZero
ifParser :: GenParser Char st Term
ifParser =
TmIf <$> (string "if" *> spaces *> arithParser)
<*> (spaces *> string "then" *> spaces *> arithParser)
<*> (spaces *> string "else" *> spaces *> arithParser)