Skip to content

Commit d078b3c

Browse files
committed
Make raw version of nameless term substitution
1 parent 24fe1d1 commit d078b3c

File tree

7 files changed

+108
-22
lines changed

7 files changed

+108
-22
lines changed

lambda-parser.cabal

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,15 @@ executable lambda-parser
3030
other-modules:
3131
Examples.Terms
3232
Parser
33-
Substitution
33+
Transformer
34+
Substitution.Named
35+
Substitution.Nameless
3436
Generator
3537

3638
-- LANGUAGE extensions used by modules in this package.
3739
-- other-extensions:
38-
build-depends: base ^>=4.17.2.0
40+
build-depends:
41+
base ^>=4.17.2.0,
42+
containers ^>= 0.7
3943
hs-source-dirs: src
4044
default-language: Haskell2010

src/Generator.hs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
module Generator where
2-
import Parser (Token(Variable, Application, Abstraction))
2+
import Parser (Term (Variable, Application, Abstraction))
3+
import Transformer (NamelessTerm (NamelessVariable, NamelessApplication, NamelessAbstraction))
34

4-
generateTerm :: Token -> String
5+
generateTerm :: Term -> String
56
generateTerm (Variable var) = [var]
6-
77
generateTerm (Application lhs rhs) = concatMap (\term -> case term of
88
var@(Variable _) -> generateTerm var
99
_ -> '(':generateTerm term ++ [')']) [lhs, rhs]
10+
generateTerm (Abstraction argument body) = 'λ':argument:'.':generateTerm body
1011

11-
generateTerm (Abstraction argument body) = 'λ':argument:'.':generateTerm body
12+
generateNamelessTerm :: NamelessTerm -> String
13+
generateNamelessTerm (NamelessVariable var) = show var
14+
generateNamelessTerm (NamelessApplication lhs rhs) = concatMap (\term -> case term of
15+
var@(NamelessVariable _) -> generateNamelessTerm var
16+
_ -> '(':generateNamelessTerm term ++ [')']) [lhs, rhs]
17+
generateNamelessTerm (NamelessAbstraction depth body) = 'λ':generateNamelessTerm body

src/Main.hs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
module Main where
22

3+
import Prelude hiding (lookup)
34
import System.IO (hSetBuffering, stdout, BufferMode (BlockBuffering))
4-
import Parser (parseTerm, Token (Variable))
5-
import Substitution (substitute)
6-
import Generator (generateTerm)
5+
import Parser (parseTerm, Term (Variable))
6+
import Substitution.Named (substitute)
7+
import Generator (generateTerm, generateNamelessTerm)
8+
import Transformer (toNameless)
9+
import Data.Map (empty, lookup)
10+
import Substitution.Nameless (substituteNameless)
711

812
main :: IO ()
913
main = do
@@ -13,6 +17,15 @@ main = do
1317
if length var /= 1
1418
then error "please provide valid variable"
1519
else do
16-
let substituteVariable = head var
17-
substituteTerm <- putStr "Input substitution term: " >> getLine
18-
putStrLn $ generateTerm $ substitute (parseTerm term) substituteVariable (parseTerm substituteTerm)
20+
let (namelessTerm, context) = toNameless (parseTerm term) 0 [] empty
21+
substituteVariable = head var `lookup` context
22+
case substituteVariable of
23+
Nothing -> error "please provide valid variable"
24+
Just index -> do
25+
substituteTerm <- putStr "Input substitution term: " >> getLine
26+
let (substituteNamelessTerm, _) = toNameless (parseTerm substituteTerm) 0 [] context
27+
putStrLn $ generateNamelessTerm $ substituteNameless namelessTerm index substituteNamelessTerm
28+
29+
-- let substituteVariable = head var
30+
-- substituteTerm <- putStr "Input substitution term: " >> getLine
31+
-- putStrLn $ generateTerm $ substitute (parseTerm term) substituteVariable (parseTerm substituteTerm)

src/Parser.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
module Parser (parseTerm, Token(Variable, Application, Abstraction)) where
1+
module Parser (parseTerm, Term(Variable, Application, Abstraction)) where
22
import Data.Char (isAlpha)
33

4-
data Token =
4+
data Term =
55
Variable Char |
6-
Application Token Token |
7-
Abstraction Char Token
6+
Application Term Term |
7+
Abstraction Char Term
88
deriving (Show)
99

1010
takeWhileClosingBracket :: String -> Int-> String
@@ -22,7 +22,7 @@ dropWhileClosingBracket (x:xs) count = dropWhileClosingBracket xs count
2222
invalidTermError :: String
2323
invalidTermError = "invalid term"
2424

25-
parseTerm :: String -> Token
25+
parseTerm :: String -> Term
2626
parseTerm [var]
2727
| isAlpha var = Variable var
2828
| otherwise = error invalidTermError

src/Substitution.hs renamed to src/Substitution/Named.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
module Substitution where
1+
module Substitution.Named where
22

3-
import Parser (Token (Application, Variable, Abstraction))
3+
import Parser (Term (Application, Variable, Abstraction))
44
import Data.Char (chr, ord)
55

6-
freeVariables :: Token -> [Char]
6+
freeVariables :: Term -> [Char]
77
freeVariables (Variable x) = [x]
88
freeVariables (Application lhs rhs) = freeVariables lhs ++ freeVariables rhs
99
freeVariables (Abstraction argument body) = filter (/= argument) $ freeVariables body
1010

11-
chooseUniqueVariable :: Token -> Token -> Char
11+
chooseUniqueVariable :: Term -> Term -> Char
1212
chooseUniqueVariable first second = let vars = freeVariables first ++ freeVariables second
1313
in chooseVariable vars 'a'
1414
where chooseVariable :: [Char] -> Char -> Char
1515
chooseVariable vars current
1616
| current `notElem` vars = current
1717
| otherwise = chooseVariable vars $ chr $ ord current + 1
1818

19-
substitute :: Token -> Char -> Token -> Token
19+
substitute :: Term -> Char -> Term -> Term
2020
substitute initial@(Variable var) x token
2121
| var == x = token
2222
| otherwise = initial

src/Substitution/Nameless.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module Substitution.Nameless where
2+
import Transformer (NamelessTerm (NamelessVariable, NamelessApplication, NamelessAbstraction), NamingContext)
3+
4+
shift :: Int -> Int -> NamelessTerm -> NamelessTerm
5+
shift c d var@(NamelessVariable k)
6+
| 0 <= k && k < c = var
7+
| otherwise = NamelessVariable (k + d)
8+
shift c d (NamelessApplication lhs rhs) = NamelessApplication (shift c d lhs) (shift c d rhs)
9+
shift c d (NamelessAbstraction depth body) = NamelessAbstraction depth (shift (c + 1) d body)
10+
11+
singleShift :: NamelessTerm -> NamelessTerm
12+
singleShift = shift 0 1
13+
14+
substituteNameless :: NamelessTerm -> Int -> NamelessTerm -> NamelessTerm
15+
substituteNameless (NamelessVariable var) x term
16+
| x == var = term
17+
| otherwise = NamelessVariable var
18+
substituteNameless (NamelessApplication lhs rhs) x term =
19+
NamelessApplication (substituteNameless lhs x term) (substituteNameless rhs x term)
20+
substituteNameless (NamelessAbstraction depth body) x term =
21+
NamelessAbstraction depth (substituteNameless body (x + 1) (singleShift term))

src/Transformer.hs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
2+
{-# HLINT ignore "Use first" #-}
3+
module Transformer where
4+
5+
import Prelude hiding (lookup)
6+
import Parser (Term (Variable, Application, Abstraction))
7+
import Data.Map (Map, member, lookup, insert, size)
8+
import Data.List (elemIndex, union)
9+
10+
data NamelessTerm
11+
= NamelessVariable Int
12+
| NamelessApplication NamelessTerm NamelessTerm
13+
| NamelessAbstraction Int NamelessTerm
14+
deriving (Show)
15+
16+
type NamingContext = Map Char Int
17+
type BoundVariable = [Char]
18+
19+
toNameless :: Term -> Int -> BoundVariable -> NamingContext -> (NamelessTerm, NamingContext)
20+
toNameless (Variable var) depth bv context = case var `elemIndex` bv of
21+
Nothing -> case lookup var context of
22+
Nothing -> let index = size context
23+
in (NamelessVariable (index + depth), insert var index context)
24+
Just index -> (NamelessVariable (index + depth), context)
25+
Just index -> (NamelessVariable index, context)
26+
27+
toNameless (Application lhs rhs) depth bv context =
28+
let namelessLhs = toNameless lhs depth bv context
29+
namelessRhs = toNameless rhs depth bv (snd namelessLhs)
30+
in (NamelessApplication (fst namelessLhs) (fst namelessRhs), snd namelessRhs)
31+
32+
toNameless (Abstraction argument body) depth bv context =
33+
let namelessBody = toNameless body (depth + 1) (insertBoundVariable argument bv) context
34+
in (NamelessAbstraction depth (fst namelessBody), snd namelessBody)
35+
where insertBoundVariable var bv = if var `elem` bv then bv else var:bv
36+
37+
-- a = Abstraction 'y' (Application (Variable 'x') (Application (Variable 'y') (Abstraction 'x' (Variable 'x'))))
38+
-- /x -> xy => Abstraction x (Application (Variable x) (Variable y))
39+
-- /01 => NamelessAbstraction 1 (NamelessApplication (Variable 0) (Variable 1))
40+
41+
-- /y -> xy/x -> x => /10/0
42+
-- (NamelessAbstraction (NamelessApplication (NamelessVariable 1) (NamelessApplication (NamelessVariable 0) (NamelessAbstraction (NamelessVariable 1))))

0 commit comments

Comments
 (0)