-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSolution.hs
73 lines (59 loc) · 2.44 KB
/
Solution.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
module Day18.Solution
( Expression (..),
advancedTable,
basicTable,
evaluateExpression,
parseExpression,
part1,
part2,
)
where
import Advent.Parser (intParser)
import Advent.Utils (fromRightOrShowError)
import Data.Functor.Identity (Identity)
import Text.Parsec
import Text.Parsec.Expr
part1 :: String -> String
part1 = show . sum . map (evaluateExpression . fromRightOrShowError . parseExpression basicTable) . lines
part2 :: String -> String
part2 = show . sum . map (evaluateExpression . fromRightOrShowError . parseExpression advancedTable) . lines
data Op = Plus | Times deriving (Show, Eq)
data Expression
= BinaryOp (Expression, Op, Expression)
| Number Int
deriving (Show, Eq)
type ExpressionOpTable = OperatorTable String () Identity Expression
evaluateExpression :: Expression -> Int
evaluateExpression (Number n) = n
evaluateExpression (BinaryOp (a, Plus, b)) = evaluateExpression a + evaluateExpression b
evaluateExpression (BinaryOp (a, Times, b)) = evaluateExpression a * evaluateExpression b
parseExpression :: ExpressionOpTable -> String -> Either ParseError Expression
parseExpression table = parse (expressionParser table) ""
expressionParser :: ExpressionOpTable -> Parsec String () Expression
expressionParser table = buildExpressionParser table termParser
where
termParser :: Parsec String () Expression
termParser = parensParser <|> numberExpressionParser
parensParser :: Parsec String () Expression
parensParser = between (char '(') (char ')') (expressionParser table)
numberExpressionParser :: Parsec String () Expression
numberExpressionParser = Number <$> intParser
basicTable :: ExpressionOpTable
basicTable = [[Infix operatorParser AssocLeft]]
where
operatorParser :: Parsec String () (Expression -> Expression -> Expression)
operatorParser = readOp <$> (space *> oneOf ['+', '*'] <* space)
advancedTable :: ExpressionOpTable
advancedTable =
[ [Infix (try plusParser) AssocLeft],
[Infix (try timesParser) AssocLeft]
]
where
timesParser :: Parsec String () (Expression -> Expression -> Expression)
timesParser = readOp <$> (space *> char '*' <* space)
plusParser :: Parsec String () (Expression -> Expression -> Expression)
plusParser = readOp <$> (space *> char '+' <* space)
readOp :: Char -> Expression -> Expression -> Expression
readOp '+' a b = BinaryOp (a, Plus, b)
readOp '*' a b = BinaryOp (a, Times, b)
readOp _ _ _ = error "This should never happen"