Slides · Talk · slides published
Making de Bruijn Succ Less
Edward Kmett
A presentation on variable binding, de Bruijn indices, and the approach used by the bound library.
Related article: Bound.
50 slides · Start reading







![subst :: Name -> Exp -> Exp -> Exp
subst x s = sub where
sub e@(Var v)
| v == x = s
| otherwise = e
sub e@(Lam v e')
| v == x = e
| v `elem` fvs = Lam v' (sub e'’)
| otherwise = Lam v (sub e’)
where v' = newId vs
e'' = subst v (Var v') e’
sub (f :@ a) = sub f :@ sub a
fvs = freeVars s
vs = fvs `union` allVars b
newId :: [Name] -> Name
newId vs = head (someEnormousPoolOfNames vs)
– go find a name that isn’t taken!
(based on code by Lennart Augustsson)](../../../assets/slides/bound/08.webp)





















![data Exp a
=V a
| Exp a :@ Exp a
| Lam (Scope () Exp a)
| Let [Scope Int Exp a] (Scope Int Exp a)
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
Instance Monad Exp where
Va >>= f = f a
(x :@ y) >>= f = (x >>= f) :@ (y >>= f)
Lam e >>= f = Lam (e >>>= f)
Let bs b >>= f = Let (map (>>>= f) bs) (b >>>= f)](../../../assets/slides/bound/30.webp)
![abstract1 :: (Monad f, Eq a) => a -> f a -> Scope () f a
abstract :: Monad f => (a -> Maybe b) -> f a -> Scope b f a
lam :: Eq a => a -> Exp a -> Exp a
lam v b = Lam (abstract1 v b)
let_ :: Eq a => [(a,Exp a)] -> Exp a -> Exp a
let_ bs b = Let (map (abstr . snd) bs) (abstr b)
where abstr = abstract (`elemIndex` map fst bs)
infixr 0 !
(!) :: Eq a => a -> Exp a -> Exp a
(!) = lam](../../../assets/slides/bound/31.webp)



![cooked :: Exp a
cooked = fromJust $ closed $ let_
[ ("False", "f" ! "t" ! V"f")
, ("True", "f" ! "t" ! V"t")
, ("if", "b" ! "t" ! "f" ! V"b" :@ V"f" :@ V"t")
, ("Zero", "z" ! "s" ! V"z")
, ("Succ", "n" ! "z" ! "s" ! V"s" :@ V"n")
, ("one", V"Succ" :@ V"Zero")
, ("two", V"Succ" :@ V"one")
, ("three", V"Succ" :@ V"two")
, ("isZero", "n" ! V"n" :@ V"True" :@ ("m" ! V"False"))
, ("const", "x" ! "y" ! V"x")
, ("Pair", "a" ! "b" ! "p" ! V"p" :@ V"a" :@ V"b")
, ("fst", "ab" ! V"ab" :@ ("a" ! "b" ! V"a"))
, ("snd", "ab" ! V"ab" :@ ("a" ! "b" ! V"b"))
, ("add", "x" ! "y" ! V"x" :@ V"y" :@ ("n" ! V"Succ" :@ (V"add" :@ V"n" :@ V"y")))
, ("mul", "x" ! "y" ! V"x" :@ V"Zero" :@ ("n" ! V"add" :@ V"y" :@ (V"mul" :@ V"n" :@ V"y")))
, ("fac", "x" ! V"x" :@ V"one" :@ ("n" ! V"mul" :@ V"x" :@ (V"fac" :@ V"n")))
, ("eqnat", "x" ! "y" ! V"x" :@ (V"y" :@ V"True" :@ (V"const" :@ V"False")) :@ ("x1" ! V"y" :@ V"False" :@ ("y1" ! V"eqnat" :@ V"x1" :@
V"y1")))
, ("sumto", "x" ! V"x" :@ V"Zero" :@ ("n" ! V"add" :@ V"x" :@ (V"sumto" :@ V"n")))
, ("n5", V"add" :@ V"two" :@ V"three")
, ("n6", V"add" :@ V"three" :@ V"three")
, ("n17", V"add" :@ V"n6" :@ (V"add" :@ V"n6" :@ V"n5"))
, ("n37", V"Succ" :@ (V"mul" :@ V"n6" :@ V"n6"))
, ("n703", V"sumto" :@ V"n37")
, ("n720", V"fac" :@ V"n6")
] (V"eqnat" :@ V"n720" :@ (V"add" :@ V"n703" :@ V"n17"))](../../../assets/slides/bound/35.webp)

![data Exp a
=V a
| Exp a :@ Exp a
| Lam !Int (Pat Exp a) (Scope Int Exp a)
| Let !Int [Scope Int Exp a] (Scope Int Exp a)
| Case (Exp a) [Alt Exp a]
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
data Pat f a
= VarP
| WildP
| AsP (Pat f a)
| ConP String [Pat f a]
| ViewP (Scope Int f a) (Pat f a)
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
data Alt f a = Alt !Int (Pat f a) (Scope Int f a)
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)](../../../assets/slides/bound/37.webp)

![data P a = P { pattern :: [a] -> Pat Exp a, bindings :: [a] }
varp :: a -> P a
varp a = P (const VarP) [a]
wildp :: P a
wildp = P (const WildP) []
conp :: String -> [P a] -> P a
conp g ps = P (ConP g . go ps) (ps >>= bindings)
where
go (P p as:ps) bs = p bs : go ps (bs ++ as)
go [] _ = []
lam :: Eq a => P a -> Exp a -> Exp a
lam (P p as) t = Lam (length as) (p []) (abstract (`elemIndex` as) t)
ghci> lam (varp "x") (V "x”)
Lam 1 VarP (Scope (V (B 0)))
ghci> lam (conp "Hello" [varp "x", wildp]) (V "y”)
Lam 1 (ConP "Hello" [VarP,WildP]) (Scope (V (F (V "y"))))](../../../assets/slides/bound/39.webp)

![My prelude-extras package defines a number of boring typeclasses like:
class Eq1 f where
(==#) :: Eq a => f a -> f a -> Bool
(/=#) :: Eq a => f a -> f a -> Bool
class Eq1 f => Ord1 f where
compare1 :: Ord a => f a -> f a -> Ordering
class Show1 f where
showsPrec1 :: Show a => Int -> f a -> ShowS
class Read1 f where
readsPrec1 :: Read a => Int -> ReadS (f a)
readList1 :: Read a => ReadS [f a]](../../../assets/slides/bound/41.webp)







![data Ix :: [*] -> * -> * where
Z :: Ix (a ': as) a
S :: Ix as b -> Ix (a ': as) b
data Vec :: (* -> *) -> [*] -> * where
HNil :: Vec f '[]
(:::) :: f b -> Vec f bs -> Vec f (b ': bs)
data Lit t where
Integer :: Integer -> Lit Integer
Double :: Double -> Lit Double
String :: String -> Lit String
data Remote :: (* -> *) -> * -> * where
Var :: f a -> Remote f a
Lit :: Lit a -> Remote f a
Lam :: Scope (Equal b) Remote f a -> Remote f (b -> a)
Let :: Vec (Scope (Ix bs) Remote f) bs -> Scope (Ix bs) Remote f a -> Remote f a
Ap :: Remote f (a -> b) -> Remote f a -> Remote f b](../../../assets/slides/bound/49.webp)

Edward Kmett
A presentation on variable binding, de Bruijn indices, and the approach used by the bound library.
Related article: Bound.