Skip to content

Commit ed6a6e1

Browse files
committed
Fix the parser to treat application without brackets as left associative
1 parent 53e7820 commit ed6a6e1

File tree

6 files changed

+37
-23
lines changed

6 files changed

+37
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ cabal install
3535
Now the executable should be located in the configured `installdir` of `cabal` (usually `~/.local/bin` or `~/.cabal/bin`).
3636

3737
## Documentation
38-
The parser traverses the lambda term and creates AST where the nodes are variables, applications and abstractions (lexing and parsing are done simultaneously). Then the substitution is done on the AST with the corresponding tokens instead of directly on the term. After the substitution, a new lambda term is generated based on the newly created AST and the result is returned as the final answer. If there are no brackets, the application term is right associative. Bear in mind that in the generated final term some brackets may be added because there is no way to know where they can be skipped without looking ahead, which the current generator does not do.
38+
The parser traverses the lambda term and creates AST where the nodes are variables, applications and abstractions (lexing and parsing are done simultaneously). Then the substitution is done on the AST with the corresponding tokens instead of directly on the term. After the substitution, a new lambda term is generated based on the newly created AST and the result is returned as the final answer. If there are no brackets, the application term is left associative. Bear in mind that in the generated final term some brackets may be added because there is no way to know where they can be skipped without looking ahead, which the current generator does not do.
3939

4040
### Grammar
4141
$` variable \Coloneqq [a-z] `$ <br>

lambda-parser.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ executable lambda-parser
3434
Substitution.Named
3535
Substitution.Nameless
3636
Generator
37+
Stack
3738

3839
-- LANGUAGE extensions used by modules in this package.
3940
-- other-extensions:

src/Main.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Substitution.Nameless (substituteNameless)
88
import System.IO (BufferMode (BlockBuffering), hSetBuffering, stdout)
99
import Transformer (toNamed, toNameless)
1010
import Prelude hiding (lookup)
11+
import Stack (emptyStack)
1112

1213
-- TODO: let the user decide which substitution to be used and how the
1314
-- result should be displayed - either as named or nameless term
@@ -19,13 +20,13 @@ main = do
1920
if length var /= 1
2021
then error "please provide valid variable"
2122
else do
22-
let (namelessTerm, context) = toNameless $ parseTerm term
23+
let (namelessTerm, context) = toNameless (parseTerm term emptyStack) empty
2324
substituteVariable = head var `lookup` context
2425
substituteTerm <- putStr "Input substitution term: " >> getLine
2526
case substituteVariable of
2627
Nothing -> putStrLn term
2728
Just index ->
28-
let (substituteNamelessTerm, updatedContext) = toNameless $ parseTerm substituteTerm
29+
let (substituteNamelessTerm, updatedContext) = toNameless (parseTerm substituteTerm emptyStack) context
2930
in putStrLn $ generateTerm $ toNamed (substituteNameless namelessTerm index substituteNamelessTerm) updatedContext
3031

3132
-- let substituteVariable = head var

src/Parser.hs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Parser (parseTerm, Term(Variable, Application, Abstraction)) where
22
import Data.Char (isAlpha)
3+
import Debug.Trace (trace)
4+
import Stack (Stack, peek, pop, emptyStack, push)
35

46
data Term =
57
Variable Char |
@@ -22,23 +24,18 @@ dropWhileClosingBracket (x:xs) count = dropWhileClosingBracket xs count
2224
invalidTermError :: String
2325
invalidTermError = "invalid term"
2426

25-
parseTerm :: String -> Term
26-
parseTerm [var]
27-
| isAlpha var = Variable var
27+
parseTerm :: String -> Stack Term -> Term
28+
parseTerm "" [term] = term
29+
parseTerm "" stack = let rhs = peek stack
30+
lhs = peek $ pop stack
31+
updatedStack = pop stack
32+
in Application (parseTerm "" updatedStack) rhs
33+
parseTerm term@('λ':argument:'.':body) stack
34+
| isAlpha argument = parseTerm "" (push stack (Abstraction argument (parseTerm body emptyStack)))
2835
| otherwise = error invalidTermError
29-
30-
parseTerm ('λ':argument:'.':body)
31-
| isAlpha argument = Abstraction argument $ parseTerm body
36+
parseTerm ('(':rest) stack = let lhs = takeWhileClosingBracket rest 1
37+
rhs = dropWhileClosingBracket rest 1
38+
in parseTerm rhs (push stack (parseTerm lhs emptyStack))
39+
parseTerm (var:rest) stack
40+
| isAlpha var = parseTerm rest (push stack (Variable var))
3241
| otherwise = error invalidTermError
33-
34-
parseTerm ('(':term) = let lhs = takeWhileClosingBracket term 1
35-
rhs = dropWhileClosingBracket term 1
36-
in if length (init term) == length lhs
37-
then parseTerm (init term)
38-
else Application (parseTerm lhs) (parseTerm rhs)
39-
40-
parseTerm (var:term)
41-
| isAlpha var = Application (Variable var) $ parseTerm term
42-
| otherwise = error invalidTermError
43-
44-
parseTerm _ = error invalidTermError

src/Stack.hs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Stack where
2+
3+
type Stack t = [t]
4+
5+
push :: Stack t -> t -> Stack t
6+
push stack element = element : stack
7+
8+
peek :: Stack t -> t
9+
peek = head
10+
11+
pop :: Stack t -> Stack t
12+
pop = tail
13+
14+
emptyStack :: Stack t
15+
emptyStack = []

src/Transformer.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ toNamelessWithContext (Abstraction argument body) depth bv context =
3535
in (NamelessAbstraction (fst namelessBody), snd namelessBody)
3636
where insertBoundVariable var bv = if var `elem` bv then bv else var:bv
3737

38-
toNameless :: Term -> (NamelessTerm, NamingContext)
39-
toNameless term = toNamelessWithContext term 0 [] empty
38+
toNameless :: Term -> NamingContext -> (NamelessTerm, NamingContext)
39+
toNameless term = toNamelessWithContext term 0 []
4040

4141
toNamedWithContext :: NamelessTerm -> BoundVariables -> NamingContext -> Term
4242
toNamedWithContext (NamelessVariable var) bv context

0 commit comments

Comments
 (0)