git.iko.soy/type-level-sets
on master help sign in
factored out some of the finite map support; and created a new finite map module
commitc3543c6097fb94d8d88bb569b69b4b851913633e authorDominic <dom.orchard@gmail.com> dateMon 19 Oct 2015, 16:57 (11 years ago) parent9139d17
4 files changed+192−54
example.hs+16−9 src/Data/Type/Map.hs+157 src/Data/Type/Set.hs+11−40 type-level-sets.cabal+8−5
example.hs+16−9
@@ -1,17 +1,24 @@
1−{-# LANGUAGE DataKinds, TypeOperators #-}
1+{-# LANGUAGE DataKinds, TypeOperators, KindSignatures, TypeFamilies, MultiParamTypeClasses #-}
22
3−import Data.Type.Set
3+import GHC.TypeLits
4+import Data.Type.Map
45
5−foo :: Set '["x" :-> Int, "z" :-> Int, "w" :-> Int]
6−foo = Ext ((Var :: (Var "x")) :-> 2) $
7− Ext ((Var :: (Var "z")) :-> 4) $
8− Ext ((Var :: (Var "w")) :-> 5) $
6+-- Specify that key-value pairs on Ints combine to an Int
7+type instance Combine Int Int = Int
8+-- Specify that Int values for matching keys should be added
9+instance Combinable Int Int where
10+ combine x y = x + y
11+
12+foo :: Map '["x" :-> Int, "z" :-> Int, "w" :-> Int]
13+foo = Ext (Var :: (Var "x")) 2 $
14+ Ext (Var :: (Var "z")) 4 $
15+ Ext (Var :: (Var "w")) 5 $
916 Empty
1017
1118
12−bar :: Set '["y" :-> Int, "w" :-> Int]
13−bar = Ext ((Var :: (Var "y")) :-> 3) $
14− Ext ((Var :: (Var "w")) :-> 1) $
19+bar :: Map '["y" :-> Int, "w" :-> Int]
20+bar = Ext (Var :: (Var "y")) 3 $
21+ Ext (Var :: (Var "w")) 1 $
1522 Empty
1623
1724-- GHC can easily infer this type, so an explicit signature not necessary
src/Data/Type/Map.hsnew file+157
@@ -0,0 +1,157 @@
1+{- This module provides type-level finite maps.
2+The implementation is similar to that shown in the paper.
3+ "Embedding effect systems in Haskell" Orchard, Petricek 2014 -}
4+
5+{-# LANGUAGE TypeOperators, PolyKinds, DataKinds, KindSignatures,
6+ TypeFamilies, UndecidableInstances, MultiParamTypeClasses,
7+ FlexibleInstances, GADTs, FlexibleContexts, ScopedTypeVariables, ConstraintKinds #-}
8+
9+module Data.Type.Map (Mapping(..), Union, Unionable, union, Var(..), Map(..),
10+ Combine, Combinable(..), Cmp,
11+ Lookup, Member, (:\)) where
12+
13+import GHC.TypeLits
14+import Data.Type.Bool
15+import Data.Type.Equality
16+import Data.Type.Set hiding (Set(..), Nub,Union,Nubable,Sortable,Unionable,append,union,quicksort,nub)
17+
18+{- Throughout, type variables
19+ 'k' ranges over "keys"
20+ 'v' ranges over "values"
21+ 'kvp' ranges over "key-value-pairs"
22+ 'm', 'n' range over "maps" -}
23+
24+-- Mappings
25+infixr 4 :->
26+{-| A key-value pair -}
27+data Mapping k v = k :-> v
28+
29+{-| Union of two finite maps -}
30+type Union m n = Nub (Sort (m :++ n))
31+
32+{-| Apply 'Combine' to values with matching key (removes duplicate keys) -}
33+type family Nub t where
34+ Nub '[] = '[]
35+ Nub '[kvp] = '[kvp]
36+ Nub ((k :-> v1) ': (k :-> v2) ': m) = Nub ((k :-> Combine v1 v2) ': m)
37+ Nub (kvp1 ': kvp2 ': s) = kvp1 ': Nub (kvp2 ': s)
38+
39+{-| Open type family for combining values in a map (that have the same key) -}
40+type family Combine (a :: v) (b :: v) :: v
41+
42+{-| Delete elements from a map by key -}
43+type family (m :: [Mapping k v]) :\ (c :: k) :: [Mapping k v] where
44+ '[] :\ k = '[]
45+ ((k :-> v) ': m) :\ k = m :\ k
46+ (kvp ': m) :\ k = kvp ': (m :\ k)
47+
48+{-| Lookup elements from a map -}
49+type family Lookup (m :: [Mapping k v]) (c :: k) :: Maybe v where
50+ Lookup '[] k = Nothing
51+ Lookup ((k :-> v) ': m) k = Just v
52+ Lookup (kvp ': m) k = Lookup m k
53+
54+{-| Membership test -}
55+type family Member (c :: k) (m :: [Mapping k v]) :: Bool where
56+ Member k '[] = False
57+ Member k ((k :-> v) ': m) = True
58+ Member k (kvp ': m) = Member k m
59+
60+-----------------------------------------------------------------
61+-- Value-level map with a type-level representation
62+
63+{-| Pair a symbol (representing a variable) with a type -}
64+data Var (k :: Symbol) = Var
65+
66+instance KnownSymbol k => Show (Var k) where
67+ show = symbolVal
68+
69+{-| A value-level heterogenously-typed Map (with type-level representation in terms of lists) -}
70+data Map (n :: [Mapping Symbol *]) where
71+ Empty :: Map '[]
72+ Ext :: Var k -> v -> Map m -> Map ((k :-> v) ': m)
73+
74+instance Show (Map '[]) where
75+ show Empty = "{}"
76+
77+instance (KnownSymbol k, Show v, Show' (Map s)) => Show (Map ((k :-> v) ': s)) where
78+ show (Ext k v s) = "{" ++ show k ++ " :-> " ++ show v ++ (show' s) ++ "}"
79+
80+class Show' t where
81+ show' :: t -> String
82+instance Show' (Map '[]) where
83+ show' Empty = ""
84+instance (KnownSymbol k, Show v, Show' (Map s)) => Show' (Map ((k :-> v) ': s)) where
85+ show' (Ext k v s) = ", " ++ show k ++ " :-> " ++ show v ++ (show' s)
86+
87+{-| Union of two finite maps -}
88+union :: (Unionable s t) => Map s -> Map t -> Map (Union s t)
89+union s t = nub (quicksort (append s t))
90+
91+type Unionable s t = (Nubable (Sort (s :++ t)), Sortable (s :++ t))
92+
93+append :: Map s -> Map t -> Map (s :++ t)
94+append Empty x = x
95+append (Ext k v xs) ys = Ext k v (append xs ys)
96+
97+type instance Cmp (k :: Symbol) (k' :: Symbol) = CmpSymbol k k'
98+type instance Cmp (k :-> v) (k' :-> v) = CmpSymbol k k'
99+
100+{-| Value-level quick sort that respects the type-level ordering -}
101+class Sortable xs where
102+ quicksort :: Map xs -> Map (Sort xs)
103+
104+instance Sortable '[] where
105+ quicksort Empty = Empty
106+
107+instance (Sortable (Filter FMin (k :-> v) xs),
108+ Sortable (Filter FMax (k :-> v) xs), FilterV FMin k v xs, FilterV FMax k v xs) => Sortable ((k :-> v) ': xs) where
109+ quicksort (Ext k v xs) = ((quicksort (less k v xs)) `append` (Ext k v Empty)) `append` (quicksort (more k v xs))
110+ where less = filterV (Proxy::(Proxy FMin))
111+ more = filterV (Proxy::(Proxy FMax))
112+
113+{- Filter out the elements less-than or greater-than-or-equal to the pivot -}
114+class FilterV (f::Flag) k v xs where
115+ filterV :: Proxy f -> Var k -> v -> Map xs -> Map (Filter f (k :-> v) xs)
116+
117+instance FilterV f k v '[] where
118+ filterV _ k v Empty = Empty
119+
120+instance (Conder ((Cmp x (k :-> v)) == LT), FilterV FMin k v xs) => FilterV FMin k v (x ': xs) where
121+ filterV f@Proxy k v (Ext k' v' xs) = cond (Proxy::(Proxy ((Cmp x (k :-> v)) == LT)))
122+ (Ext k' v' (filterV f k v xs)) (filterV f k v xs)
123+
124+instance (Conder (((Cmp x (k :-> v)) == GT) || ((Cmp x (k :-> v)) == EQ)), FilterV FMax k v xs) => FilterV FMax k v (x ': xs) where
125+ filterV f@Proxy k v (Ext k' v' xs) = cond (Proxy::(Proxy (((Cmp x (k :-> v)) == GT) || ((Cmp x (k :-> v)) == EQ))))
126+ (Ext k' v' (filterV f k v xs)) (filterV f k v xs)
127+
128+class Combinable t t' where
129+ combine :: t -> t' -> Combine t t'
130+
131+class Nubable t where
132+ nub :: Map t -> Map (Nub t)
133+
134+instance Nubable '[] where
135+ nub Empty = Empty
136+
137+instance Nubable '[e] where
138+ nub (Ext k v Empty) = Ext k v Empty
139+
140+instance {-# OVERLAPPING #-}
141+ (Combinable v v', Nubable ((k :-> Combine v v') ': s)) => Nubable ((k :-> v) ': (k :-> v') ': s) where
142+ nub (Ext k v (Ext k' v' s)) = nub (Ext k (combine v v') s)
143+
144+instance {-# OVERLAPPING #-}
145+ (Nub (e ': f ': s) ~ (e ': Nub (f ': s)),
146+ Nubable (f ': s)) => Nubable (e ': f ': s) where
147+ nub (Ext k v (Ext k' v' s)) = Ext k v (nub (Ext k' v' s))
148+
149+class Conder g where
150+ cond :: Proxy g -> Map s -> Map t -> Map (If g s t)
151+
152+instance Conder True where
153+ cond _ s t = s
154+
155+instance Conder False where
156+ cond _ s t = t
157+
src/Data/Type/Set.hs+11−40
@@ -3,9 +3,8 @@
33 UndecidableInstances, ConstraintKinds, ScopedTypeVariables #-}
44
55module Data.Type.Set (Set(..), Union, Unionable, union, quicksort, append,
6− Sort, Sortable, Append(..), Split(..), Cmp,
7− Nub, Nubable(..), AsSet, asSet, IsSet, Subset(..),
8− (:->)(..), Var(..), Delete(..)) where
6+ Sort, Sortable, (:++), Split(..), Cmp, Filter, Flag(..),
7+ Nub, Nubable(..), AsSet, asSet, IsSet, Subset(..), Delete(..), Proxy(..)) where
98
109import GHC.TypeLits
1110import Data.Type.Bool
@@ -13,9 +12,11 @@ import Data.Type.Equality
1312
1413data Proxy (p :: k) = Proxy
1514
16−{-| Core Set definition, in terms of lists -}
15+-- Value-level 'Set' representation, essentially a list
1716data Set (n :: [*]) where
17+ {-| Construct an empty set-}
1818 Empty :: Set '[]
19+ {-| Extend a set with an element -}
1920 Ext :: e -> Set s -> Set (e ': s)
2021
2122instance Show (Set '[]) where
@@ -50,25 +51,22 @@ type SetProperties f = (Union f '[] ~ f, Split f '[] f,
5051{-- Union --}
5152
5253{-| Union of sets -}
53−type Union s t = Nub (Sort (Append s t))
54+type Union s t = Nub (Sort (s :++ t))
5455
5556union :: (Unionable s t) => Set s -> Set t -> Set (Union s t)
5657union s t = nub (quicksort (append s t))
5758
58−type Unionable s t = (Sortable (Append s t), Nubable (Sort (Append s t)))
59+type Unionable s t = (Sortable (s :++ t), Nubable (Sort (s :++ t)))
5960
6061{-| List append (essentially set disjoint union) -}
61−type family Append (s :: [k]) (t :: [k]) :: [k] where
62− Append '[] t = t
63− Append (x ': xs) ys = x ': (Append xs ys)
62+type family (:++) (x :: [k]) (y :: [k]) :: [k] where
63+ '[] :++ xs = xs
64+ (x ': xs) :++ ys = x ': (xs :++ ys)
6465
65−append :: Set s -> Set t -> Set (Append s t)
66+append :: Set s -> Set t -> Set (s :++ t)
6667append Empty x = x
6768append (Ext e xs) ys = Ext e (append xs ys)
6869
69−{-| Useful alias for append -}
70−type (s :: [k]) :++ (t :: [k]) = Append s t
71−
7270{-| Splitting a union a set, given the sets we want to split it into -}
7371class Split s t st where
7472 -- where st ~ Union s t
@@ -195,30 +193,3 @@ instance Conder False where
195193
196194type family Cmp (a :: k) (b :: k) :: Ordering
197195
198−{-| Pair a symbol (representing a variable) with a type -}
199−infixl 2 :->
200−data (k :: Symbol) :-> (v :: *) = (Var k) :-> v
201−
202−data Var (k :: Symbol) where Var :: Var k
203− {- Some special defaults for some common names -}
204− X :: Var "x"
205− Y :: Var "y"
206− Z :: Var "z"
207−
208−
209−instance (Show (Var k), Show v) => Show (k :-> v) where
210− show (k :-> v) = "(" ++ show k ++ " :-> " ++ show v ++ ")"
211−instance Show (Var "x") where
212− show X = "x"
213− show Var = "Var"
214−instance Show (Var "y") where
215− show Y = "y"
216− show Var = "Var"
217−instance Show (Var "z") where
218− show Z = "z"
219− show Var = "Var"
220−instance Show (Var v) where
221− show _ = "Var"
222−
223−{-| Symbol comparison -}
224−type instance Cmp (v :-> a) (u :-> b) = CmpSymbol v u
type-level-sets.cabal+8−5
@@ -1,15 +1,17 @@
11name: type-level-sets
2−version: 0.5.1
3−synopsis: Type-level sets (with value-level counterparts and various operations)
2+version: 0.6
3+synopsis: Type-level sets and finite maps (with value-level counterparts and various operations)
44description:
5− This package provides type-level sets (no duplicates, sorted to provide a nomral form) via 'Set',
6− with value-level counterparts. Described in the paper \"Embedding effect systems in Haskell\" by Dominic Orchard
5+ This package provides type-level sets (no duplicates, sorted to provide a normal form) via 'Set' and type-level
6+ maps via 'Map', with value-level counterparts.
7+ .
8+ Described in the paper \"Embedding effect systems in Haskell\" by Dominic Orchard
79 and Tomas Petricek <http://www.cl.cam.ac.uk/~dao29/publ/haskell14-effects.pdf> (Haskell Symposium, 2014)
810 .
911 Here is a brief example:
1012 .
1113 >
12− > import Data.Type.Set
14+ > import Data.Type.Map
1315 >
1416 > foo :: Set '["x" :-> Int, "z" :-> Int, "w" :-> Int]
1517 > foo = Ext ((Var :: (Var "x")) :-> 2) $
@@ -56,6 +58,7 @@ library
5658
5759
5860 exposed-modules: Data.Type.Set
61+ Data.Type.Map
5962
6063 build-depends: base >= 4.7.0.0 && < 5,
6164 ghc-prim