parsing, update readme
This commit is contained in:
parent
098cf0832a
commit
f64bf8be2b
3 changed files with 43 additions and 33 deletions
|
|
@ -4,7 +4,8 @@ A (very WIP) lambda expression evaluator and debugger.
|
||||||
|
|
||||||
I'd like to build the following:
|
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
|
- [ ] alpha/beta reduction to beta normal
|
||||||
- [ ] substitutions for known abstractions (numbers can be written and are displayed as numbers rather than lambda terms)
|
- [ ] substitutions for known abstractions (numbers can be written and are displayed as numbers rather than lambda terms)
|
||||||
- [ ] persisted variables
|
- [ ] persisted variables
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,47 @@
|
||||||
module Parser where
|
module Parser where
|
||||||
|
|
||||||
import Control.Monad (void)
|
import Control.Monad (void)
|
||||||
|
import Data.Char (isLetter)
|
||||||
import Text.Parsec
|
import Text.Parsec
|
||||||
import Text.Parsec.String (Parser)
|
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)
|
deriving (Eq)
|
||||||
|
|
||||||
instance Show Expr where
|
instance Show Expr where
|
||||||
show (Variable name) = name
|
show (Variable name) = name
|
||||||
show (Abstraction (arg, body)) = "λ" ++ arg ++ ". " ++ show body
|
show (Abstraction arg body) = "λ" ++ arg ++ ". " ++ show body
|
||||||
show (Application (f, x)) = "(" ++ show f ++ " " ++ show x ++ ")"
|
show (Application f x) = "(" ++ show f ++ " " ++ show x ++ ")"
|
||||||
|
|
||||||
ws :: Parser ()
|
ws :: Parser ()
|
||||||
ws = skipMany (void space)
|
ws = skipMany (void space)
|
||||||
|
|
||||||
|
lexeme :: Parser a -> Parser a
|
||||||
|
lexeme p = p <* ws
|
||||||
|
|
||||||
variable :: Parser Expr
|
variable :: Parser Expr
|
||||||
variable = do
|
variable = lexeme $ do
|
||||||
name <- many letter
|
name <- many1 (satisfy (\c -> isLetter c && c /= 'λ'))
|
||||||
return $ Variable name
|
return $ Variable name
|
||||||
|
|
||||||
abstraction :: Parser Expr
|
abstraction :: Parser Expr
|
||||||
abstraction = do
|
abstraction = lexeme $ do
|
||||||
_ <- void (char 'λ')
|
_ <- void (char 'λ')
|
||||||
variable <- many letter
|
name <- many letter
|
||||||
body <- parseExpr
|
_ <- void (char '.' >> ws)
|
||||||
return $ Abstraction (variable, body)
|
body <- application
|
||||||
|
return $ Abstraction name body
|
||||||
|
|
||||||
parseExpr :: Parser Expr
|
application :: Parser Expr
|
||||||
parseExpr = variable <|> abstraction
|
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 :: 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)
|
Left err -> Left (show err)
|
||||||
Right val -> Right val
|
Right val -> Right val
|
||||||
|
|
|
||||||
|
|
@ -9,39 +9,37 @@ spec = do
|
||||||
it "can parse variable" $
|
it "can parse variable" $
|
||||||
(parse "x") `shouldBe` Right (Variable "x")
|
(parse "x") `shouldBe` Right (Variable "x")
|
||||||
it "can parse identity abstraction" $
|
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" $
|
it "can parse mockingbird of identity" $
|
||||||
(parse "(λx.x x) (λx.x)") -- (λx.x) (λx.x) -> (λx.x)
|
(parse "(λx.x x) (λx.x)") -- (λx.x) (λx.x) -> (λx.x)
|
||||||
`shouldBe` Right
|
`shouldBe` Right
|
||||||
( Application
|
( Application
|
||||||
( Abstraction
|
( Abstraction
|
||||||
( "x",
|
"x"
|
||||||
Application
|
( Application
|
||||||
( Variable "x",
|
(Variable "x")
|
||||||
Variable "x"
|
(Variable "x")
|
||||||
)
|
)
|
||||||
),
|
|
||||||
Abstraction ("x", Variable "x")
|
|
||||||
)
|
)
|
||||||
|
(Abstraction "x" (Variable "x"))
|
||||||
)
|
)
|
||||||
it "it can parse successor" $
|
it "it can parse successor" $
|
||||||
(parse "λn.λf.λx.f (n f x)")
|
(parse "λn.λf.λx.f (n f x)")
|
||||||
`shouldBe` Right
|
`shouldBe` Right
|
||||||
( Abstraction
|
( Abstraction
|
||||||
( "n",
|
"n"
|
||||||
Abstraction
|
( Abstraction
|
||||||
( "f",
|
"f"
|
||||||
Abstraction
|
( Abstraction
|
||||||
( "x",
|
"x"
|
||||||
Application
|
|
||||||
( Variable "f",
|
|
||||||
Application
|
|
||||||
( Application
|
( Application
|
||||||
( Variable "n",
|
(Variable "f")
|
||||||
Variable "f"
|
( Application
|
||||||
),
|
( Application
|
||||||
Variable "x"
|
(Variable "n")
|
||||||
)
|
(Variable "f")
|
||||||
|
)
|
||||||
|
(Variable "x")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue