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"
```

# 感想

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