Skip to content

Commit 1832029

Browse files
committed
Added first-order language example
1 parent f6f487c commit 1832029

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

ebu-examples/embedding-by-unembedding-examples.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ library
4545
Unembedding.Examples.STLC
4646
Unembedding.Examples.Forall
4747
Unembedding.Examples.Modal
48+
Unembedding.Examples.FirstOrder
4849

4950
hs-source-dirs: src
5051
default-language: Haskell2010
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
{-
2+
3+
Embedding of a simple first-order language with the fix-point operator.
4+
5+
-}
6+
{-# OPTIONS_GHC -Wno-missing-export-lists #-}
7+
{-# LANGUAGE DataKinds #-}
8+
{-# LANGUAGE DerivingStrategies #-}
9+
{-# LANGUAGE FlexibleContexts #-}
10+
{-# LANGUAGE FlexibleInstances #-}
11+
{-# LANGUAGE FunctionalDependencies #-}
12+
{-# LANGUAGE GADTs #-}
13+
{-# LANGUAGE PolyKinds #-}
14+
{-# LANGUAGE RankNTypes #-}
15+
{-# LANGUAGE ScopedTypeVariables #-}
16+
{-# LANGUAGE StandaloneDeriving #-}
17+
{-# LANGUAGE TypeFamilies #-}
18+
{-# LANGUAGE TypeOperators #-}
19+
20+
module Unembedding.Examples.FirstOrder where
21+
import Data.Proxy (Proxy (..))
22+
import qualified Unembedding as UE
23+
import qualified Unembedding.Env as UE
24+
import Unembedding.Env (Env (..))
25+
26+
data ValType = VInt | VBool
27+
data FunType = I ValType | ValType :~> FunType
28+
29+
infixr 0 :~>
30+
31+
-- First-order de Bruijn representation for a first-order language with fix.
32+
data FOLang fenv venv a where
33+
FLam :: FOLang fenv (a : venv) b -> FOLang fenv venv (a :~> b)
34+
FApp :: FOLang fenv venv (a :~> b) -> FOLang fenv venv (I a) -> FOLang fenv venv b
35+
FVar :: UE.Ix venv a -> FOLang fenv venv (I a)
36+
FFun :: UE.Ix fenv f -> FOLang fenv venv f
37+
FFix :: FOLang (f : fenv) venv f -> FOLang fenv venv f
38+
39+
deriving stock instance Show (FOLang fenv venv a)
40+
41+
weakenVar :: Proxy b -> Proxy venv -> UE.Env Proxy as -> UE.Ix (UE.Append as venv) a -> UE.Ix (UE.Append as (b : venv)) a
42+
weakenVar _ _ (_ :. _) UE.IxZ = UE.IxZ
43+
weakenVar pb pvenv (_ :. as) (UE.IxS x) = UE.IxS (weakenVar pb pvenv as x)
44+
weakenVar _ _ ENil ix = UE.IxS ix
45+
46+
weaken2 :: Proxy b -> Proxy venv -> UE.Env Proxy as -> FOLang fenv (UE.Append as venv) a -> FOLang fenv (UE.Append as (b : venv)) a
47+
weaken2 pb pvenv as (FLam e) = FLam $ weaken2 pb pvenv (Proxy :. as) e
48+
weaken2 pb pvenv as (FApp e1 e2) = FApp (weaken2 pb pvenv as e1) (weaken2 pb pvenv as e2)
49+
weaken2 pb pvenv as (FVar ix) = FVar (weakenVar pb pvenv as ix)
50+
weaken2 _ _ _ (FFun ix) = FFun ix
51+
weaken2 pb pvenv as (FFix e) = FFix $ weaken2 pb pvenv as e
52+
53+
54+
55+
-- Its HOAS representation (in tagless-final style)
56+
--
57+
-- Observe that it involves two semantic domains. Also, `lam` and `fix` bind
58+
-- variables from different domains.
59+
class HFOLang i e | e -> i where
60+
lam :: (i a -> e b) -> e (a :~> b)
61+
var :: i a -> e (I a)
62+
app :: e (a :~> b) -> e (I a) -> e b
63+
fix :: (e a -> e a) -> e a
64+
65+
-- Intermediate type class
66+
class HFOLang' e where
67+
lam' :: e (a : venv) b -> e venv (a :~> b)
68+
app' :: e venv (a :~> b) -> e venv (I a) -> e venv b
69+
var' :: UE.Ix venv a -> e venv (I a)
70+
fix' :: (e venv a -> e venv a) -> e venv a
71+
72+
-- newtype wrapper for the above e
73+
newtype E e (env :: [ValType]) (a :: FunType) = E { unE :: e env a }
74+
75+
instance UE.Weakenable e => UE.Weakenable (E e) where
76+
weaken (E x) = E (UE.weaken x)
77+
78+
instance (HFOLang' e, UE.Weakenable e) => HFOLang (UE.EnvI UE.Ix) (UE.EnvI (E e)) where
79+
lam = UE.liftSOn' (UE.ol1 :. ENil) Proxy $ \(E e) -> E (lam' e)
80+
app = UE.liftFO2 $ \(E e1) (E e2) -> E (app' e1 e2)
81+
fix = UE.liftSOnGen (UE.DimNested (UE.K UE.E) :. ENil) (Proxy :: Proxy UE.Ix) $ \f -> E $ fix' (unE . f . E)
82+
var = UE.liftFO1' $ E . var'
83+
84+
-- type family Fst (a :: (k , k')) :: k where
85+
-- Fst '(a , b) = a
86+
87+
-- type family Snd (a :: (k , k')) :: k' where
88+
-- Snd '(a , b) = b
89+
90+
-- newtype WrapL fenv venva = WrapL (FOLang fenv (Fst venva) (Snd venva))
91+
92+
93+
-- newtype SwFOLang venv fenv a = SwFOLang (FOLang fenv venv a)
94+
newtype Sw f venv fenv a = Sw (f fenv venv a)
95+
96+
newtype Wrap e venv a = Wrap { unWrap :: UE.EnvI (Sw e venv) a }
97+
98+
instance UE.LiftVariables (Sw FOLang venv) where
99+
type Var (Sw FOLang venv) = UE.Ix
100+
liftVar ix = Sw $ FFun ix
101+
102+
instance HFOLang' (Wrap FOLang) where
103+
lam' (Wrap ex) = Wrap $ UE.liftFO1' (\(Sw e) -> Sw $ FLam e) ex
104+
app' (Wrap ex1) (Wrap ex2) = Wrap $ UE.liftFO2 (\(Sw e1) (Sw e2) -> Sw (FApp e1 e2)) ex1 ex2
105+
var' ix = Wrap $ UE.liftFO0 $ Sw $ FVar ix
106+
fix' f = Wrap $ UE.liftSOn (UE.ol1 :. ENil) fixSem (unWrap . f . Wrap)
107+
where
108+
fixSem (Sw e) = Sw $ FFix e
109+
110+
instance UE.Weakenable (Wrap FOLang) where
111+
weaken (Wrap w) = Wrap $ UE.liftFO1' (\(Sw e) -> Sw (weaken2 Proxy Proxy ENil e)) w
112+
113+
convert :: forall a. (forall i e. HFOLang i e => e a) -> FOLang '[] '[] a
114+
convert h =
115+
let h' :: forall e. (UE.Weakenable e, HFOLang' e) => e '[] a
116+
h' = unE $ UE.runClose h
117+
Sw r = UE.runClose (unWrap h') -- TODO: Is it really safe?
118+
in r
119+
120+
-- >>> convert $ fix (\_ -> lam $ \x -> lam $ \y -> var x)
121+
-- FFix (FLam (FLam (FVar (IxS IxZ))))
122+
123+
-- >>> convert $ lam $ \x -> lam $ \y -> fix (\_ -> lam $ \x -> lam $ \y -> var x) `app` var x `app` var y
124+
-- FLam (FLam (FApp (FApp (FFix (FLam (FLam (FVar (IxS IxZ))))) (FVar (IxS IxZ))) (FVar IxZ)))
125+
126+
-- >>> convert $ fix (\f -> lam $ \x -> app f (var x))
127+
-- FFix (FLam (FApp (FFun IxZ) (FVar IxZ)))

0 commit comments

Comments
 (0)