{-# LANGUAGE InstanceSigs #-}
module Lessons.Lesson14 where
import qualified Data.List as L
data Term = Var String | Abs String Term | App Term Term
instance Show Term where
show :: Term -> String
show :: Term -> String
show (Var String
n) = String
n
show (Abs String
n Term
t) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"(/|", String
n, String
".", Term -> String
forall a. Show a => a -> String
show Term
t, String
")"]
show (App Term
t1 Term
t2) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"(", Term -> String
forall a. Show a => a -> String
show Term
t1, String
" ", Term -> String
forall a. Show a => a -> String
show Term
t2, String
")"]
tru :: Term
tru :: Term
tru = String -> Term -> Term
Abs String
"t" (String -> Term -> Term
Abs String
"f" (String -> Term
Var String
"t"))
fls :: Term
fls :: Term
fls = String -> Term -> Term
Abs String
"t" (String -> Term -> Term
Abs String
"f" (String -> Term
Var String
"f"))
c0 :: Term
c0 :: Term
c0 = String -> Term -> Term
Abs String
"s" (String -> Term -> Term
Abs String
"z" (String -> Term
Var String
"z"))
c2 :: Term
c2 :: Term
c2 = String -> Term -> Term
Abs String
"s" (String -> Term -> Term
Abs String
"z" (Term -> Term -> Term
App (String -> Term
Var String
"s") (Term -> Term -> Term
App (String -> Term
Var String
"s") (String -> Term
Var String
"z"))))
apps :: [Term] -> Term
apps :: [Term] -> Term
apps [] = String -> Term
forall a. HasCallStack => String -> a
error String
"Empty application"
apps [Term
_] = String -> Term
forall a. HasCallStack => String -> a
error String
"Two terms needed for application"
apps (Term
t1 : Term
t2 : [Term]
ts) = Term -> [Term] -> Term
apps' (Term -> Term -> Term
App Term
t1 Term
t2) [Term]
ts
where
apps' :: Term -> [Term] -> Term
apps' Term
t [] = Term
t
apps' Term
t (Term
x : [Term]
xs) = Term -> [Term] -> Term
apps' (Term -> Term -> Term
App Term
t Term
x) [Term]
xs
land :: Term
land :: Term
land = String -> Term -> Term
Abs String
"b" (Term -> Term) -> Term -> Term
forall a b. (a -> b) -> a -> b
$ String -> Term -> Term
Abs String
"c" (Term -> Term) -> Term -> Term
forall a b. (a -> b) -> a -> b
$ [Term] -> Term
apps [String -> Term
Var String
"b", String -> Term
Var String
"c", Term
fls]
expr :: Term
expr :: Term
expr = [Term] -> Term
apps [Term
land, Term
tru, Term
tru]
data ITerm
= IVar Int
| IAbs ITerm
| IApp ITerm ITerm
deriving (ITerm -> ITerm -> Bool
(ITerm -> ITerm -> Bool) -> (ITerm -> ITerm -> Bool) -> Eq ITerm
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ITerm -> ITerm -> Bool
== :: ITerm -> ITerm -> Bool
$c/= :: ITerm -> ITerm -> Bool
/= :: ITerm -> ITerm -> Bool
Eq)
instance Show ITerm where
show :: ITerm -> String
show :: ITerm -> String
show (IVar Int
i) = Int -> String
forall a. Show a => a -> String
show Int
i
show (IAbs ITerm
t) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"(/|.", ITerm -> String
forall a. Show a => a -> String
show ITerm
t, String
")"]
show (IApp ITerm
t1 ITerm
t2) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"(", ITerm -> String
forall a. Show a => a -> String
show ITerm
t1, String
" ", ITerm -> String
forall a. Show a => a -> String
show ITerm
t2, String
")"]
deBruijnIndices :: [String] -> Term -> ITerm
deBruijnIndices :: [String] -> Term -> ITerm
deBruijnIndices [String]
ctx Term
t = [String] -> Term -> ITerm
walk [] Term
t
where
walk :: [String] -> Term -> ITerm
walk [String]
stack (Var String
n) = Int -> ITerm
IVar ([String] -> String -> Int
findInd [String]
stack String
n)
walk [String]
stack (Abs String
n Term
t) = ITerm -> ITerm
IAbs ([String] -> Term -> ITerm
walk (String
n String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
stack) Term
t)
walk [String]
stack (App Term
t1 Term
t2) = ITerm -> ITerm -> ITerm
IApp ([String] -> Term -> ITerm
walk [String]
stack Term
t1) ([String] -> Term -> ITerm
walk [String]
stack Term
t2)
findInd :: [String] -> String -> Int
findInd [String]
stack String
n =
case (String
n String -> [String] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
`L.elemIndex` [String]
stack, String
n String -> [String] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
`L.elemIndex` [String]
ctx) of
(Just Int
i, Maybe Int
_) -> Int
i
(Maybe Int
Nothing, Just Int
i) -> [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
L.length [String]
stack Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i
(Maybe Int, Maybe Int)
_ -> String -> Int
forall a. HasCallStack => String -> a
error (String -> Int) -> String -> Int
forall a b. (a -> b) -> a -> b
$ String
"No index for free variable " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
n
termShift :: Int -> ITerm -> ITerm
termShift :: Int -> ITerm -> ITerm
termShift Int
d = Int -> ITerm -> ITerm
walk Int
0
where
walk :: Int -> ITerm -> ITerm
walk Int
c (IVar Int
x)
| Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
c = Int -> ITerm
IVar (Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d)
| Bool
otherwise = Int -> ITerm
IVar Int
x
walk Int
c (IAbs ITerm
t') = ITerm -> ITerm
IAbs (Int -> ITerm -> ITerm
walk (Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ITerm
t')
walk Int
c (IApp ITerm
t1 ITerm
t2) = ITerm -> ITerm -> ITerm
IApp (Int -> ITerm -> ITerm
walk Int
c ITerm
t1) (Int -> ITerm -> ITerm
walk Int
c ITerm
t2)
termSubst :: Int -> ITerm -> ITerm -> ITerm
termSubst :: Int -> ITerm -> ITerm -> ITerm
termSubst Int
j ITerm
s = Int -> ITerm -> ITerm
walk Int
0
where
walk :: Int -> ITerm -> ITerm
walk Int
c (IVar Int
x)
| Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
jInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
c = Int -> ITerm -> ITerm
termShift Int
c ITerm
s
| Bool
otherwise = Int -> ITerm
IVar Int
x
walk Int
c (IAbs ITerm
t') = ITerm -> ITerm
IAbs (Int -> ITerm -> ITerm
walk (Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ITerm
t')
walk Int
c (IApp ITerm
t1 ITerm
t2) = ITerm -> ITerm -> ITerm
IApp (Int -> ITerm -> ITerm
walk Int
c ITerm
t1) (Int -> ITerm -> ITerm
walk Int
c ITerm
t2)
termSubstTop :: ITerm -> ITerm -> ITerm
termSubstTop :: ITerm -> ITerm -> ITerm
termSubstTop ITerm
s ITerm
t = Int -> ITerm -> ITerm
termShift (-Int
1) (Int -> ITerm -> ITerm -> ITerm
termSubst Int
0 (Int -> ITerm -> ITerm
termShift Int
1 ITerm
s) ITerm
t)
isVal :: ITerm -> Bool
isVal :: ITerm -> Bool
isVal (IAbs ITerm
_) = Bool
True
isVal ITerm
_ = Bool
False
eval :: ITerm -> ITerm
eval :: ITerm -> ITerm
eval (IApp (IAbs ITerm
t') ITerm
v2) | ITerm -> Bool
isVal ITerm
v2 = ITerm -> ITerm -> ITerm
termSubstTop ITerm
v2 ITerm
t'
eval (IApp ITerm
v1 ITerm
t2) | ITerm -> Bool
isVal ITerm
v1 = ITerm -> ITerm -> ITerm
IApp ITerm
v1 (ITerm -> ITerm
eval ITerm
t2)
eval (IApp ITerm
t1 ITerm
t2) = ITerm -> ITerm -> ITerm
IApp (ITerm -> ITerm
eval ITerm
t1) ITerm
t2
eval ITerm
t = String -> ITerm
forall a. HasCallStack => String -> a
error (String -> ITerm) -> String -> ITerm
forall a b. (a -> b) -> a -> b
$ String
"No rule to apply for: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ITerm -> String
forall a. Show a => a -> String
show ITerm
t