parsing, update readme

This commit is contained in:
jackjohn7 2026-05-15 02:02:57 -05:00
parent 098cf0832a
commit f64bf8be2b
3 changed files with 43 additions and 33 deletions

View file

@ -4,7 +4,8 @@ A (very WIP) lambda expression evaluator and debugger.
I'd like to build the following:
- [ ] parsing with parsec
- [X] parsing with parsec
- need to harden tests a bit more but existing tests pass
- [ ] alpha/beta reduction to beta normal
- [ ] substitutions for known abstractions (numbers can be written and are displayed as numbers rather than lambda terms)
- [ ] persisted variables

View file

@ -1,36 +1,47 @@
module Parser where
import Control.Monad (void)
import Data.Char (isLetter)
import Text.Parsec
import Text.Parsec.String (Parser)
data Expr = Variable String | Abstraction (String, Expr) | Application (Expr, Expr)
data Expr = Variable String | Abstraction String Expr | Application Expr Expr
deriving (Eq)
instance Show Expr where
show (Variable name) = name
show (Abstraction (arg, body)) = "λ" ++ arg ++ ". " ++ show body
show (Application (f, x)) = "(" ++ show f ++ " " ++ show x ++ ")"
show (Abstraction arg body) = "λ" ++ arg ++ ". " ++ show body
show (Application f x) = "(" ++ show f ++ " " ++ show x ++ ")"
ws :: Parser ()
ws = skipMany (void space)
lexeme :: Parser a -> Parser a
lexeme p = p <* ws
variable :: Parser Expr
variable = do
name <- many letter
variable = lexeme $ do
name <- many1 (satisfy (\c -> isLetter c && c /= 'λ'))
return $ Variable name
abstraction :: Parser Expr
abstraction = do
abstraction = lexeme $ do
_ <- void (char 'λ')
variable <- many letter
body <- parseExpr
return $ Abstraction (variable, body)
name <- many letter
_ <- void (char '.' >> ws)
body <- application
return $ Abstraction name body
parseExpr :: Parser Expr
parseExpr = variable <|> abstraction
application :: Parser Expr
application = lexeme $ chainl1 atom (return Application)
parens :: Parser Expr
parens = lexeme $ between (char '(') (char ')') application
atom :: Parser Expr
atom = variable <|> abstraction <|> parens
parse :: String -> Either String Expr
parse content = case Text.Parsec.parse parseExpr "<input>" content of
parse content = case Text.Parsec.parse application "<input>" content of
Left err -> Left (show err)
Right val -> Right val

View file

@ -9,39 +9,37 @@ spec = do
it "can parse variable" $
(parse "x") `shouldBe` Right (Variable "x")
it "can parse identity abstraction" $
(parse "λx.x") `shouldBe` Right (Abstraction ("x", Variable "x"))
(parse "λx.x") `shouldBe` Right (Abstraction "x" (Variable "x"))
it "can parse mockingbird of identity" $
(parse "(λx.x x) (λx.x)") -- (λx.x) (λx.x) -> (λx.x)
`shouldBe` Right
( Application
( Abstraction
( "x",
Application
( Variable "x",
Variable "x"
)
),
Abstraction ("x", Variable "x")
"x"
( Application
(Variable "x")
(Variable "x")
)
)
(Abstraction "x" (Variable "x"))
)
it "it can parse successor" $
(parse "λn.λf.λx.f (n f x)")
`shouldBe` Right
( Abstraction
( "n",
Abstraction
( "f",
Abstraction
( "x",
Application
( Variable "f",
Application
"n"
( Abstraction
"f"
( Abstraction
"x"
( Application
(Variable "f")
( Application
( Application
( Variable "n",
Variable "f"
),
Variable "x"
(Variable "n")
(Variable "f")
)
(Variable "x")
)
)
)