-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConv.hs
145 lines (115 loc) · 4.52 KB
/
Conv.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
module Conv where
import Data.Kind (Constraint, Type)
import Data.SOP (NP (..))
import Data.Type.Equality ((:~:) (..), (:~~:) (..))
import Type.Reflection (TypeRep, Typeable, eqTypeRep, typeRep)
-------------------------------------------------------------------------------
-- Types
-------------------------------------------------------------------------------
data Ty
= Fun Ty Ty
| Emp
deriving Show
type a ~> b = Fun a b
infixr 0 ~>
type Ctx = [Ty]
-- For convenience, we'll use Typeable as singleton for types.
type STy :: Ty -> Type
type STy a = TypeRep a
type STyI :: Ty -> Constraint
type STyI a = Typeable a
sty :: STyI a => STy a
sty = typeRep
-------------------------------------------------------------------------------
-- de Bruijn
-------------------------------------------------------------------------------
type Idx :: [k] -> k -> Type
data Idx xs a where
IZ :: Idx (a : xs) a
IS :: Idx xs a -> Idx (b : xs) a
deriving instance Show (Idx xs a)
lookupNP :: NP f xs -> Idx xs x -> f x
lookupNP Nil x = case x of {}
lookupNP (x :* _) IZ = x
lookupNP (_ :* xs) (IS i) = lookupNP xs i
type DB :: Ctx -> Ty -> Type
data DB ctx ty where
DVar :: Idx ctx ty -> DB ctx ty
DApp :: DB ctx (Fun a b) -> DB ctx a -> DB ctx b
DLam :: STyI a => DB (a : ctx) b -> DB ctx (Fun a b)
deriving instance Show (DB ctx ty)
-------------------------------------------------------------------------------
-- PHOAS
-------------------------------------------------------------------------------
type PHOAS :: (Ty -> Type) -> Ty -> Type
data PHOAS var ty where
PVar :: var ty -> PHOAS var ty
PApp :: PHOAS var (Fun a b) -> PHOAS var a -> PHOAS var b
PLam :: STyI a => (var a -> PHOAS var b) -> PHOAS var (Fun a b)
plam :: STyI a => (PHOAS var a -> PHOAS var b) -> PHOAS var (Fun a b)
plam f = PLam $ \x -> f (PVar x)
-------------------------------------------------------------------------------
-- de Bruijn to PHOAS
-------------------------------------------------------------------------------
toPHOAS :: NP var ctx -> DB ctx a -> PHOAS var a
toPHOAS env (DVar i) = PVar (lookupNP env i)
toPHOAS env (DApp f t) = PApp (toPHOAS env f) (toPHOAS env t)
toPHOAS env (DLam t) = PLam $ \x -> toPHOAS (x :* env) t
-------------------------------------------------------------------------------
-- PHOAS to de Bruijn
-------------------------------------------------------------------------------
-- We cannot really do the same as in Agda,
-- but we can get close.
-- a singleton for Ctx
type SCtx :: Ctx -> Type
data SCtx ctx where
SNil :: SCtx '[]
SCons :: STy a -> SCtx ctx -> SCtx (a : ctx)
eqSCtx :: SCtx xs -> SCtx ys -> Maybe (xs :~: ys)
eqSCtx SNil SNil = Just Refl
eqSCtx (SCons x xs) (SCons y ys) = do
HRefl <- eqTypeRep x y
Refl <- eqSCtx xs ys
return Refl
eqSCtx SNil SCons {} = Nothing
eqSCtx SCons {} SNil = Nothing
-- If you squint hard enough, this approach starts to look like ones in
-- Generic Conversions of Abstract Syntax Representations or
-- Unembedding Domain-Specific Languages
--
-- but it still resembles our Agda solution.
--
-- The difference is that we don't have well-formedness predicate,
-- but rather check well-formedness condition inside makeVar.
--
-- The drawback is that we need equality procedure on types.
-- In well-scoped representation we'd just compare lengths of contexts;
-- and we could compare the lengths here too, even strongly
-- relying on parametricity (and using unsafeCoerce).
--
type ToCtx :: Ty -> Type
data ToCtx a where
ToCtx :: STy a -> SCtx ctx -> ToCtx a
deriving instance Show (ToCtx ctx)
deriving instance Show (SCtx ctx)
makeVar :: forall a sfx ctx. STy a -> SCtx sfx -> SCtx ctx -> Idx ctx a
makeVar a sfx ctx0 = go ctx0
where
go :: SCtx ctx' -> Idx ctx' a
go SNil = error $ "Should not happen: " ++
show (SCons a sfx) ++ " is not suffix of " ++ show ctx0
go (SCons b ctx)
| Just HRefl <- eqTypeRep a b
, Just Refl <- eqSCtx sfx ctx
= IZ
| otherwise
= IS (makeVar a sfx ctx)
toDB :: SCtx ctx -> PHOAS ToCtx a -> DB ctx a
toDB ctx (PVar (ToCtx a sfx)) = DVar (makeVar a sfx ctx)
toDB ctx (PApp f t) = DApp (toDB ctx f) (toDB ctx t)
toDB ctx (PLam f) = DLam (toDB (SCons sty ctx) (f (ToCtx sty ctx)))
-------------------------------------------------------------------------------
-- Example
-------------------------------------------------------------------------------
ex :: (Typeable a, Typeable b) => PHOAS v ((a ~> b) ~> a ~> b)
ex = plam $ \f -> plam $ \x -> PApp f x