Posted at

Parsecで論理演算

More than 3 years have passed since last update.

ふと思い立ったのでParsecを軽くさわってみました。


やりたいこと

簡単な論理演算をやりたい。


  • AND

  • OR

  • NOT

NOT > AND > ORの順に結合するとする


実装

import Text.Parsec

data Exp = And Exp Exp | Or Exp Exp | Not Exp | T | F deriving Show

expr :: Parsec String st Exp
expr = do
t <- term
Or t <$> (string "or" *> expr) <|> pure t

term :: Parsec String st Exp
term = do
b <- inverse
And b <$> (string "and" *> term) <|> pure b

inverse :: Parsec String st Exp
inverse = spaces *> (Not <$> (string "not" *> spaces *> bool) <|> bool)

bool :: Parsec String st Exp
bool = toBool <$> (oneOf ['t', 'f'] <* spaces)
where
toBool 't' = T
toBool 'f' = F

parseE :: String -> Either ParseError Exp
parseE = parse expr "* ParseError *"

calc :: String -> Either ParseError Bool
calc s = _calc <$> parseE s
where
_calc :: Exp -> Bool
_calc (And a b) = (_calc a) && (_calc b)
_calc (Or a b) = (_calc a) || (_calc b)
_calc (Not a) = not (_calc a)
_calc T = True
_calc F = False


結果

*Main> parseE "not f and t and f or not t"  

Right (Or (And (Not F) (And T F)) (Not T))

*Main> calc "not f and t and f or not t"
Right False

*Main> parseE "not f and t or f and not t"
Right (Or (And (Not F) T) (And F (Not T)))

*Main> calc "not f and t or f and not t"
Right True

*Main> calc "a"
Left "* ParseError *" (line 1, column 1):
unexpected "a"
expecting white space or "not"


感想

スペースを無視するところをもうちょっとうまくやりたい。


参考にしたページ

http://qiita.com/tadokoro/items/2b5900d8dd762f3bc829

http://utotch.blogspot.jp/2011/12/haskell-parser.html