git.iko.soy/type-level-sets
on master help sign in
6 files changed+123−50
since splitsnapshots
unifiedsplit
changelog.md+5 example2.hs+9 src/Data/Type/Map.hs+46−24 src/Data/Type/Set.hs+43−7 stack.yaml+1−1 type-level-sets.cabal+19−18
changelog.mdnew file+5
@@ -0,0 +1,5 @@
1+ # v0.8.9.0
2+
3+ - GHC 8.4 and 8.6 support.
4+ - Fixed bug in the delete operation.
5+ - Non-membership predicates
example2.hs+9
@@ -1,4 +1,5 @@
11{-# LANGUAGE DataKinds, TypeOperators, TypeFamilies, GADTs, StandaloneDeriving #-}
2+{-# LANGUAGE FlexibleContexts #-}
23
34import GHC.TypeLits
45import Data.Type.Set
@@ -19,3 +20,11 @@ bar = asSet $ Ext (S (S Z)) (Ext (S Z) (Ext (S Z) Empty))
1920
2021-- foobar :: Set '[Natural 0, Natural 1, Natural 2, Natural 3]
2122foobar = foo `union` bar
23+
24+nonMemberTest :: NonMember (Natural 0) as => Set as -> ()
25+nonMemberTest set = ()
26+
27+-- nonMemberTest meep is well typed
28+meep = asSet $ Ext (S Z) (Ext (S (S Z)) Empty)
29+-- nonMemberTest morp is ill typed
30+morp = asSet $ Ext (S Z) (Ext (S (S Z)) (Ext Z Empty))
src/Data/Type/Map.hs+46−24
@@ -46,17 +46,17 @@ type family Combine (a :: v) (b :: v) :: v
4646
4747{-| Delete elements from a map by key -}
4848type family (m :: [Mapping k v]) :\ (c :: k) :: [Mapping k v] where
49− '[] :\ k = '[]
50− ((k :-> v) ': m) :\ k = m :\ k
51− (kvp ': m) :\ k = kvp ': (m :\ k)
49+ '[] :\ k = '[]
50+ ((k :-> v) ': m) :\ k = m :\ k
51+ (kvp ': m) :\ k = kvp ': (m :\ k)
5252
53−{-| Lookup elements from a map -}
53+{-| Type-level lookup of elements from a map -}
5454type family Lookup (m :: [Mapping k v]) (c :: k) :: Maybe v where
5555 Lookup '[] k = Nothing
5656 Lookup ((k :-> v) ': m) k = Just v
5757 Lookup (kvp ': m) k = Lookup m k
5858
59−{-| Membership test -}
59+{-| Membership test as type function -}
6060type family Member (c :: k) (m :: [Mapping k v]) :: Bool where
6161 Member k '[] = False
6262 Member k ((k :-> v) ': m) = True
@@ -84,7 +84,7 @@ class IsMember v t m where
8484instance {-# OVERLAPS #-} IsMember v t ((v ':-> t) ': m) where
8585 lookp _ (Ext _ x _) = x
8686
87−instance IsMember v t m => IsMember v t (x ': m) where
87+instance {-# OVERLAPPABLE #-} IsMember v t m => IsMember v t (x ': m) where
8888 lookp v (Ext _ _ m) = lookp v m
8989
9090
@@ -100,8 +100,12 @@ instance {-# OVERLAPS #-} Updatable v t ((v ':-> s) ': m) ((v ':-> t) ': m) wher
100100instance Updatable v t m n => Updatable v t ((w ':-> y) ': m) ((w ':-> y) ': n) where
101101 update (Ext w y m) v x = Ext w y (update m v x)
102102
103−instance Updatable v t '[] '[v ':-> t] where
104− update Empty v x = Ext v x Empty
103+-- instance Updatable v t '[] '[v ':-> t] where
104+-- update Empty v x = Ext v x Empty
105+
106+instance Updatable v t s ((v ':-> t) ': s) where
107+ update xs v x = Ext v x xs
108+
105109
106110{-| Predicate to check if in normalised map form -}
107111type IsMap s = (s ~ Nub (Sort s))
@@ -117,7 +121,7 @@ instance Show (Map '[]) where
117121 show Empty = "{}"
118122
119123instance (KnownSymbol k, Show v, Show' (Map s)) => Show (Map ((k :-> v) ': s)) where
120− show (Ext k v s) = "{" ++ show k ++ " :-> " ++ show v ++ (show' s) ++ "}"
124+ show (Ext k v s) = "{" ++ show k ++ " :-> " ++ show v ++ show' s ++ "}"
121125
122126class Show' t where
123127 show' :: t -> String
@@ -129,15 +133,22 @@ instance (KnownSymbol k, Show v, Show' (Map s)) => Show' (Map ((k :-> v) ': s))
129133instance Eq (Map '[]) where
130134 Empty == Empty = True
131135
132−instance (KnownSymbol k, Eq (Var k), Eq v, Eq (Map s)) => Eq (Map ((k :-> v) ': s)) where
133− (Ext k v m) == (Ext k' v' m') = k == k' && v == v' && m == m'
136+instance (Eq v, Eq (Map s)) => Eq (Map ((k :-> v) ': s)) where
137+ (Ext Var v m) == (Ext Var v' m') = v == v' && m == m'
134138
135−{-| Union of two finite maps -}
139+instance Ord (Map '[]) where
140+ compare Empty Empty = EQ
141+
142+instance (Ord v, Ord (Map s)) => Ord (Map ((k :-> v) ': s)) where
143+ compare (Ext Var v m) (Ext Var v' m') = compare v v' `mappend` compare m m'
144+
145+{-| Union of two finite maps (normalising) -}
136146union :: (Unionable s t) => Map s -> Map t -> Map (Union s t)
137147union s t = nub (quicksort (append s t))
138148
139149type Unionable s t = (Nubable (Sort (s :++ t)), Sortable (s :++ t))
140150
151+{-| Append of two finite maps (non normalising) -}
141152append :: Map s -> Map t -> Map (s :++ t)
142153append Empty x = x
143154append (Ext k v xs) ys = Ext k v (append xs ys)
@@ -152,11 +163,15 @@ class Sortable xs where
152163instance Sortable '[] where
153164 quicksort Empty = Empty
154165
155−instance (Sortable (Filter FMin (k :-> v) xs),
156− Sortable (Filter FMax (k :-> v) xs), FilterV FMin k v xs, FilterV FMax k v xs) => Sortable ((k :-> v) ': xs) where
157− quicksort (Ext k v xs) = ((quicksort (less k v xs)) `append` (Ext k v Empty)) `append` (quicksort (more k v xs))
158− where less = filterV (Proxy::(Proxy FMin))
159− more = filterV (Proxy::(Proxy FMax))
166+instance (Sortable (Filter FMin (k :-> v) xs)
167+ , Sortable (Filter FMax (k :-> v) xs)
168+ , FilterV FMin k v xs
169+ , FilterV FMax k v xs) => Sortable ((k :-> v) ': xs) where
170+ quicksort (Ext k v xs) =
171+ quicksort (less k v xs) `append` Ext k v Empty `append` quicksort (more k v xs)
172+ where
173+ less = filterV (Proxy::(Proxy FMin))
174+ more = filterV (Proxy::(Proxy FMax))
160175
161176{- Filter out the elements less-than or greater-than-or-equal to the pivot -}
162177class FilterV (f::Flag) k v xs where
@@ -165,13 +180,19 @@ class FilterV (f::Flag) k v xs where
165180instance FilterV f k v '[] where
166181 filterV _ k v Empty = Empty
167182
168−instance (Conder ((Cmp x (k :-> v)) == LT), FilterV FMin k v xs) => FilterV FMin k v (x ': xs) where
169− filterV f@Proxy k v (Ext k' v' xs) = cond (Proxy::(Proxy ((Cmp x (k :-> v)) == LT)))
170− (Ext k' v' (filterV f k v xs)) (filterV f k v xs)
183+instance (Conder (Cmp x (k :-> v) == LT), FilterV FMin k v xs) => FilterV FMin k v (x ': xs) where
184+ filterV f@Proxy k v (Ext k' v' xs) =
185+ cond (Proxy::(Proxy (Cmp x (k :-> v) == LT)))
186+ (Ext k' v' (filterV f k v xs))
187+ (filterV f k v xs)
171188
172−instance (Conder (((Cmp x (k :-> v)) == GT) || ((Cmp x (k :-> v)) == EQ)), FilterV FMax k v xs) => FilterV FMax k v (x ': xs) where
173− filterV f@Proxy k v (Ext k' v' xs) = cond (Proxy::(Proxy (((Cmp x (k :-> v)) == GT) || ((Cmp x (k :-> v)) == EQ))))
174− (Ext k' v' (filterV f k v xs)) (filterV f k v xs)
189+instance
190+ (Conder ((Cmp x (k :-> v) == GT) || (Cmp x (k :-> v) == EQ)), FilterV FMax k v xs)
191+ => FilterV FMax k v (x ': xs) where
192+ filterV f@Proxy k v (Ext k' v' xs) =
193+ cond (Proxy::(Proxy ((Cmp x (k :-> v) == GT) || (Cmp x (k :-> v) == EQ))))
194+ (Ext k' v' (filterV f k v xs))
195+ (filterV f k v xs)
175196
176197class Combinable t t' where
177198 combine :: t -> t' -> Combine t t'
@@ -191,7 +212,8 @@ instance {-# OVERLAPPABLE #-}
191212 nub (Ext k v (Ext k' v' s)) = Ext k v (nub (Ext k' v' s))
192213
193214instance {-# OVERLAPS #-}
194− (Combinable v v', Nubable ((k :-> Combine v v') ': s)) => Nubable ((k :-> v) ': (k :-> v') ': s) where
215+ (Combinable v v', Nubable ((k :-> Combine v v') ': s))
216+ => Nubable ((k :-> v) ': (k :-> v') ': s) where
195217 nub (Ext k v (Ext k' v' s)) = nub (Ext k (combine v v') s)
196218
197219
src/Data/Type/Set.hs+43−7
@@ -1,12 +1,13 @@
11{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeOperators, TypeFamilies,
22 MultiParamTypeClasses, FlexibleInstances, PolyKinds,
33 FlexibleContexts, UndecidableInstances, ConstraintKinds,
4− ScopedTypeVariables #-}
4+ ScopedTypeVariables, TypeInType #-}
55
66module Data.Type.Set (Set(..), Union, Unionable, union, quicksort, append,
77 Sort, Sortable, (:++), Split(..), Cmp, Filter, Flag(..),
88 Nub, Nubable(..), AsSet, asSet, IsSet, Subset(..),
9− Delete(..), Proxy(..)) where
9+ Delete(..), Proxy(..), remove, Remove, (:\),
10+ Member(..), NonMember, MemberP(..)) where
1011
1112import GHC.TypeLits
1213import Data.Type.Bool
@@ -15,7 +16,7 @@ import Data.Type.Equality
1516data Proxy (p :: k) = Proxy
1617
1718-- Value-level 'Set' representation, essentially a list
18−data Set (n :: [*]) where
19+data Set (n :: [k]) where
1920 {--| Construct an empty set -}
2021 Empty :: Set '[]
2122 {--| Extend a set with an element -}
@@ -73,6 +74,25 @@ append :: Set s -> Set t -> Set (s :++ t)
7374append Empty x = x
7475append (Ext e xs) ys = Ext e (append xs ys)
7576
77+{-| Delete elements from a set -}
78+type family (m :: [k]) :\ (x :: k) :: [k] where
79+ '[] :\ x = '[]
80+ (x ': xs) :\ x = xs :\ x
81+ (y ': xs) :\ x = y ': (xs :\ x)
82+
83+class Remove s t where
84+ remove :: Set s -> Proxy t -> Set (s :\ t)
85+
86+instance Remove '[] t where
87+ remove Empty Proxy = Empty
88+
89+instance {-# OVERLAPS #-} Remove xs x => Remove (x ': xs) x where
90+ remove (Ext _ xs) x@Proxy = remove xs x
91+
92+instance {-# OVERLAPPABLE #-} (((y : xs) :\ x) ~ (y : (xs :\ x)), Remove xs x)
93+ => Remove (y ': xs) x where
94+ remove (Ext y xs) (x@Proxy) = Ext y (remove xs x)
95+
7696{-| Splitting a union a set, given the sets we want to split it into -}
7797class Split s t st where
7898 -- where st ~ Union s t
@@ -93,8 +113,6 @@ instance {-# OVERLAPS #-} (Split s t st) => Split s (x ': t) (x ': st) where
93113 split (Ext x st) = let (s, t) = split st
94114 in (s, Ext x t)
95115
96−
97−
98116{-| Remove duplicates from a sorted list -}
99117type family Nub t where
100118 Nub '[] = '[]
@@ -130,10 +148,10 @@ class Subset s t where
130148instance Subset '[] '[] where
131149 subset xs = Empty
132150
133−instance Subset s t => Subset s (x ': t) where
151+instance {-# OVERLAPPABLE #-} Subset s t => Subset s (x ': t) where
134152 subset (Ext _ xs) = subset xs
135153
136−instance Subset s t => Subset (x ': s) (x ': t) where
154+instance {-# OVERLAPS #-} Subset s t => Subset (x ': s) (x ': t) where
137155 subset (Ext x xs) = Ext x (subset xs)
138156
139157
@@ -198,3 +216,21 @@ instance Conder False where
198216{-| Open-family for the ordering operation in the sort -}
199217
200218type family Cmp (a :: k) (b :: k) :: Ordering
219+
220+{-| Membership of an element in a set, with an acommanying
221+ value-level function that returns a bool -}
222+class Member a s where
223+ member :: Proxy a -> Set s -> Bool
224+
225+instance {-# OVERLAPS #-} Member a (a ': s) where
226+ member _ (Ext x _) = True
227+
228+instance {-# OVERLAPPABLE #-} Member a s => Member a (b ': s) where
229+ member a (Ext _ xs) = member a xs
230+
231+type family MemberP a s :: Bool where
232+ MemberP a '[] = False
233+ MemberP a (a ': s) = True
234+ MemberP a (b ': s) = MemberP a s
235+
236+type NonMember a s = MemberP a s ~ False
stack.yaml+1−1
@@ -1,7 +1,7 @@
11# For more information, see: https://github.com/commercialhaskell/stack/wiki/stack.yaml
22
33# Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)
4−resolver: nightly-2016-07-18
4+resolver: lts-12.7
55
66# Local packages, usually specified by relative directory name
77packages:
type-level-sets.cabal+19−18
@@ -1,14 +1,14 @@
11name: type-level-sets
2−version: 0.8.0.0
2+version: 0.8.9.0
33synopsis: Type-level sets and finite maps (with value-level counterparts)
4−description:
4+description:
55 This package provides type-level sets (no duplicates, sorted to provide a normal form) via 'Set' and type-level
66 finite maps via 'Map', with value-level counterparts.
77 .
8− Described in the paper \"Embedding effect systems in Haskell\" by Dominic Orchard
9− and Tomas Petricek <http://www.cl.cam.ac.uk/~dao29/publ/haskell14-effects.pdf> (Haskell Symposium, 2014). This version now uses Quicksort to normalise the representation.
8+ Described in the paper \"Embedding effect systems in Haskell\" by Dominic Orchard
9+ and Tomas Petricek <http://www.cl.cam.ac.uk/~dao29/publ/haskell14-effects.pdf> (Haskell Symposium, 2014). This version now uses Quicksort to normalise the representation.
1010 .
11− Here is a brief example for finite maps:
11+ Here is a brief example for finite maps:
1212 .
1313 >
1414 > import Data.Type.Map
@@ -19,26 +19,26 @@ description:
1919 > combine x y = x + y
2020 >
2121 > foo :: Map '["x" :-> Int, "z" :-> Bool, "w" :-> Int]
22− > foo = Ext (Var :: (Var "x")) 2
23− > $ Ext (Var :: (Var "z")) True
24− > $ Ext (Var :: (Var "w")) 5
25− > $ Empty
22+ > foo = Ext (Var :: (Var "x")) 2
23+ > $ Ext (Var :: (Var "z")) True
24+ > $ Ext (Var :: (Var "w")) 5
25+ > $ Empty
2626 >
2727 > bar :: Map '["y" :-> Int, "w" :-> Int]
2828 > bar = Ext (Var :: (Var "y")) 3
2929 > $ Ext (Var :: (Var "w")) 1
3030 > $ Empty
31− >
31+ >
3232 > -- foobar :: Map '["w" :-> Int, "x" :-> Int, "y" :-> Int, "z" :-> Bool]
3333 > foobar = foo `union` bar
3434 .
3535 The 'Map' type for 'foobar' here shows the normalised form (sorted with no duplicates).
3636 The type signatures is commented out as it can be infered. Running the example we get:
3737 .
38− > >>> foobar
38+ > >>> foobar
3939 > {w :-> 6, x :-> 2, y :-> 3, z :-> True}
4040 .
41− Thus, we see that the values for \"w\" are added together.
41+ Thus, we see that the values for \"w\" are added together.
4242 For sets, here is an example:
4343 .
4444 > import GHC.TypeLits
@@ -48,7 +48,7 @@ description:
4848 > data Natural (a :: Nat) where
4949 > Z :: Natural 0
5050 > S :: Natural n -> Natural (n + 1)
51− >
51+ >
5252 > -- foo :: Set '[Natural 0, Natural 1, Natural 3]
5353 > foo = asSet $ Ext (S Z) (Ext (S (S (S Z))) (Ext Z Empty))
5454 >
@@ -63,15 +63,15 @@ description:
6363license: BSD3
6464license-file: LICENSE
6565category: Type System, Data Structures
66−copyright: 2013-16 University of Cambridge
66+copyright: 2013-18 University of Kent
6767author: Dominic Orchard
6868maintainer: Dominic Orchard
6969stability: experimental
7070build-type: Simple
7171cabal-version: >= 1.6
72−tested-with: GHC >= 8.0.1
72+tested-with: GHC >= 8.2.2
7373
74−extra-source-files: example.hs, example2.hs
74+extra-source-files: example.hs, example2.hs, changelog.md
7575
7676
7777source-repository head
@@ -80,10 +80,11 @@ source-repository head
8080
8181library
8282 hs-source-dirs: src
83+ other-extensions: TypeInType
8384
8485
8586 exposed-modules: Data.Type.Set
8687 Data.Type.Map
87−
88+
8889 build-depends: base < 5,
89− ghc-prim
90+ ghc-prim