1
Fork 0
tagless-final-parsing/parser-gadt/app/Main.hs

117 lines
2.9 KiB
Haskell
Raw Normal View History

2021-12-20 13:16:50 +00:00
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
module Main where
import qualified Control.Monad.Combinators.Expr as E
import qualified Text.Megaparsec as M
import qualified Text.Megaparsec.Char as MC
import qualified Text.Megaparsec.Char.Lexer as ML
import Control.Applicative ((<|>))
import Data.Char (isDigit)
import Data.Foldable (foldl')
import Data.Functor (($>))
import Data.Text (Text)
import Data.Void (Void)
import Numeric (readDec)
import System.Environment (getArgs)
-- ========================================
-- GADT
-- ========================================
data Expr a where
EInt :: Integer -> Expr Integer
EBool :: Bool -> Expr Bool
EAdd :: Expr Integer -> Expr Integer -> Expr Integer
ESub :: Expr Integer -> Expr Integer -> Expr Integer
EAnd :: Expr Bool -> Expr Bool -> Expr Bool
EOr :: Expr Bool -> Expr Bool -> Expr Bool
deriving instance Show (Expr Integer)
deriving instance Show (Expr Bool)
eval :: forall a. Expr a -> Either Bool Integer
eval (EInt e) = Right e
eval (EBool e) = Left e
eval (EAdd lhs rhs) =
let Right r1 = eval lhs
Right r2 = eval rhs
in Right (r1 + r2)
eval (ESub lhs rhs) =
let Right r1 = eval lhs
Right r2 = eval rhs
in Right (r1 - r2)
eval (EAnd lhs rhs) =
let Left r1 = eval lhs
Left r2 = eval rhs
in Left (r1 && r2)
eval (EOr lhs rhs) =
let Left r1 = eval lhs
Left r2 = eval rhs
in Left (r1 || r2)
-- ========================================
-- Unused parser code
-- ========================================
type Parser = M.Parsec Void Text
space :: Parser ()
space = ML.space MC.space1 M.empty M.empty
{-# INLINE space #-}
lexeme_ :: forall a. Parser a -> Parser a
lexeme_ = ML.lexeme $ MC.space1 <|> M.eof
{-# INLINE lexeme_ #-}
symbol :: Text -> Parser Text
symbol = ML.symbol space
{-# INLINE symbol #-}
parens :: forall a. Parser a -> Parser a
parens = M.between (symbol "(") (symbol ")")
{-# INLINE parens #-}
boolean :: Parser Bool
boolean = lexeme_ do
MC.string "true" $> True <|> MC.string "false" $> False
{-# INLINE boolean #-}
integer :: Parser Integer
integer = lexeme_ do
i <- M.some $ M.satisfy isDigit
case readDec i of
[(value, "")] -> pure value
_ -> fail "integer"
{-# INLINE integer #-}
{-
Couldn't match type `Bool` with `Integer`
parseExpr = E.makeExprParser parseTerm
[ [binary "+" EAdd, binary "-" ESub]
, [binary "&&" EAnd, binary "||" EOr]
]
where
binary name f = E.InfixL (f <$ symbol name)
parseTerm = parens parseExpr <|>
EInt <$> integer <|>
EBool <$> boolean
-}
-- ========================================
-- Main
-- ========================================
main :: IO ()
main = do
[count] <- map read <$> getArgs
let expr = foldl' EAdd (EInt 0) $ take count (EInt <$> [1..])
print $ {-# SCC "evaluated" #-} eval expr