Created
December 22, 2010 16:16
-
-
Save sjoerdvisscher/751702 to your computer and use it in GitHub Desktop.
Generic programming with indexed types (ala Conor McBride)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE TypeOperators, TypeFamilies, GADTs, UndecidableInstances, RankNTypes, MultiParamTypeClasses, TypeSynonymInstances #-} | |
data End i | |
data Arg s r | |
data Rec i r | |
type family Apply f a :: * | |
data Univ desc is r i where | |
End :: is i -> Univ (End i) is r i | |
Arg :: s j -> Univ (Apply rest j) is r i -> Univ (Arg s rest) is r i | |
Rec :: r j -> Univ rest is r i -> Univ (Rec j rest) is r i | |
data Fix d is i = In { out :: Univ d is (Fix d is) i } | |
con :: is i -> (Univ (End i) is r i -> Univ d is (Fix d is) j) -> Fix d is j | |
con i f = In $ f (End i) | |
getIndex :: Fix d is i -> is i | |
getIndex (In x) = getIndex' x | |
where | |
getIndex' :: Univ d is r i -> is i | |
getIndex' (End i) = i | |
getIndex' (Arg _ rest) = getIndex' rest | |
getIndex' (Rec _ rest) = getIndex' rest | |
newtype K a i = K { unK :: a } | |
data Const d | |
type instance Apply (Const d) a = d | |
type l :*: r = Arg l (Const r) | |
data L | |
data R | |
data LR i where | |
L :: LR L | |
R :: LR R | |
data LRF l r | |
type instance Apply (LRF l r) L = l | |
type instance Apply (LRF l r) R = r | |
type l :+: r = Arg LR (LRF l r) | |
type x :~> y = forall i. x i -> y i | |
hmap :: (x :~> y) -> Univ d is x :~> Univ d is y | |
hmap _ (End i) = End i | |
hmap f (Arg s rest) = Arg s (hmap f rest) | |
hmap f (Rec x rest) = Rec (f x) (hmap f rest) | |
fold :: (Univ d is x :~> x) -> Fix d is :~> x | |
fold phi = phi . hmap (fold phi) . out | |
type NatD = End () :+: Rec () (End ()) | |
type Nat = Fix NatD (K ()) () | |
zero :: Nat | |
zero = con (K ()) $ Arg L | |
suc :: Nat -> Nat | |
suc n = con (K ()) $ Arg R . Rec n | |
addA :: Nat -> Univ NatD (K ()) (K Nat) :~> K Nat | |
addA y (Arg L (End _)) = K y | |
addA _ (Arg R (Rec (K n) (End _))) = K $ suc n | |
add :: Nat -> Nat -> Nat | |
add x y = unK $ fold (addA y) x | |
data Z | |
data S n | |
data N i where | |
Z :: N Z | |
S :: N n -> N (S n) | |
type family AddN a b :: * | |
type instance AddN Z b = b | |
type instance AddN (S n) b = S (AddN n b) | |
data VecF | |
type instance Apply VecF n = Rec n (End (S n)) | |
type VecD a = End Z :+: (K a :*: Arg N VecF) | |
type Vec a = Fix (VecD a) N | |
nil :: Vec a Z | |
nil = con Z $ Arg L | |
cons :: a -> Vec a n -> Vec a (S n) | |
cons x xs = con (S n) $ Arg R . Arg (K x) . Arg n . Rec xs | |
where n = getIndex xs | |
data ConcatF a n m = ConcatF { getConcatF :: Vec a (AddN m n) } | |
concatA :: Vec a n -> Univ (VecD a) N (ConcatF a n) :~> ConcatF a n | |
concatA ys (Arg L (End _)) = ConcatF ys | |
concatA _ (Arg R (Arg (K x) (Arg _ (Rec (ConcatF xs) (End _))))) = ConcatF $ cons x xs | |
concat :: Vec a m -> Vec a n -> Vec a (AddN m n) | |
concat xs ys = getConcatF $ fold (concatA ys) xs | |
class Fam fam where | |
data DescF fam :: * | |
from :: fam a -> a -> Univ (Arg fam (DescF fam)) fam (I0 fam) a | |
to :: fam a -> Univ (Arg fam (DescF fam)) fam (I0 fam) a -> a | |
class IsFamMember fam a where proof :: fam a | |
newtype I0 fam a = I0 { unI0 :: IsFamMember fam a => a } | |
compos :: Fam fam => (forall a. fam a -> a -> a) -> fam a -> a -> a | |
compos f p = to p . hmap (\(I0 x) -> I0 $ f proof x) . from p | |
data Expr = Const Int | |
| Add Expr Expr | |
| Mul Expr Expr | |
| EVar Var | |
| Let Decl Expr | |
data Decl = Var := Expr | |
| Seq Decl Decl | |
type Var = String | |
data AST i where | |
Expr :: AST Expr | |
Decl :: AST Decl | |
Var :: AST Var | |
instance IsFamMember AST Expr where proof = Expr | |
instance IsFamMember AST Decl where proof = Decl | |
instance IsFamMember AST Var where proof = Var | |
type instance Apply (DescF AST) Expr = | |
(K Int :*: End Expr) | |
:+: (Rec Expr (Rec Expr (End Expr))) | |
:+: (Rec Expr (Rec Expr (End Expr))) | |
:+: (Rec Var (End Expr)) | |
:+: (Rec Decl (Rec Expr (End Expr))) | |
type instance Apply (DescF AST) Decl = | |
(Rec Var (Rec Expr (End Decl))) | |
:+: (Rec Decl (Rec Decl (End Decl))) | |
type instance Apply (DescF AST) Var = | |
(K String :*: End Var) | |
instance Fam AST where | |
from Expr (Const i) = Arg Expr . Arg L . Arg L . Arg L . Arg L . Arg (K i) $ End Expr | |
from Expr (Add e1 e2) = Arg Expr . Arg L . Arg L . Arg L . Arg R . Rec (I0 e1) . Rec (I0 e2) $ End Expr | |
from Expr (Mul e1 e2) = Arg Expr . Arg L . Arg L . Arg R . Rec (I0 e1) . Rec (I0 e2) $ End Expr | |
from Expr (EVar v) = Arg Expr . Arg L . Arg R . Rec (I0 v) $ End Expr | |
from Expr (Let d e) = Arg Expr . Arg R . Rec (I0 d) . Rec (I0 e) $ End Expr | |
from Decl (v := e) = Arg Decl . Arg L . Rec (I0 v) . Rec (I0 e) $ End Decl | |
from Decl (Seq d1 d2) = Arg Decl . Arg R . Rec (I0 d1) . Rec (I0 d2) $ End Decl | |
from Var s = Arg Var . Arg (K s) $ End Var | |
to Expr (Arg Expr (Arg L (Arg L (Arg L (Arg L (Arg (K i) (End Expr))))))) = Const i | |
to Expr (Arg Expr (Arg L (Arg L (Arg L (Arg R (Rec (I0 e1) (Rec (I0 e2) (End Expr)))))))) = Add e1 e2 | |
to Expr (Arg Expr (Arg L (Arg L (Arg R (Rec (I0 e1) (Rec (I0 e2) (End Expr))))))) = Mul e1 e2 | |
to Expr (Arg Expr (Arg L (Arg R (Rec (I0 v) (End Expr))))) = EVar v | |
to Expr (Arg Expr (Arg R (Rec (I0 d) (Rec (I0 e) (End Expr))))) = Let d e | |
to Decl (Arg Decl (Arg L (Rec (I0 v) (Rec (I0 e) (End Decl))))) = v := e | |
to Decl (Arg Decl (Arg R (Rec (I0 d1) (Rec (I0 d2) (End Decl))))) = Seq d1 d2 | |
to Var (Arg Var (Arg (K s) (End Var))) = s | |
renameVar :: Expr -> Expr | |
renameVar = renameVar' Expr | |
where | |
renameVar' :: AST a -> a -> a | |
renameVar' Var s = s ++ "_" | |
renameVar' p x = compos renameVar' p x |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment