{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleInstances #-}
module Main where
import Prelude hiding (lookup)
import Char (ord)
import qualified Data.Map as Map
import Control.Monad ((>=>))
import Generics.Instant
-- Generalized tries, as from http://www.haskell.org/haskellwiki/GHC/Type_families#An_associated_data_type_example
class Representable k => GMapKey k where
data GMap k :: * -> *
empty :: GMap k v
lookup :: k -> GMap k v -> Maybe v
insert :: k -> v -> GMap k v -> GMap k v
instance GMapKey Int where
data GMap Int v = GMapInt (Map.Map Int v)
empty = GMapInt Map.empty
lookup k (GMapInt m) = Map.lookup k m
insert k v (GMapInt m) = GMapInt (Map.insert k v m)
instance GMapKey Char where
data GMap Char v = GMapChar (GMap Int v)
empty = GMapChar empty
lookup k (GMapChar m) = lookup (ord k) m
insert k v (GMapChar m) = GMapChar (insert (ord k) v m)
instance GMapKey U where
data GMap U v = GMapUnit (Maybe v)
empty = GMapUnit Nothing
lookup U (GMapUnit v) = v
insert U v (GMapUnit _) = GMapUnit $ Just v
instance (GMapKey a, GMapKey b) => GMapKey (a :*: b) where
data GMap (a :*: b) v = GMapProd (GMap a (GMap b v))
empty = GMapProd empty
lookup (a :*: b) (GMapProd gm) = lookup a gm >>= lookup b
insert (a :*: b) v (GMapProd gm) =
GMapProd $ case lookup a gm of
Nothing -> insert a (insert b v empty) gm
Just gm2 -> insert a (insert b v gm2 ) gm
instance (GMapKey a, GMapKey b) => GMapKey (a :+: b) where
data GMap (a :+: b) v = GMapSum (GMap a v) (GMap b v)
empty = GMapSum empty empty
lookup (L a) (GMapSum gm1 _gm2) = lookup a gm1
lookup (R b) (GMapSum _gm1 gm2 ) = lookup b gm2
insert (L a) v (GMapSum gm1 gm2) = GMapSum (insert a v gm1) gm2
insert (R a) v (GMapSum gm1 gm2) = GMapSum gm1 (insert a v gm2)
-- Uninteresting cases, but necessary
instance (GMapKey a) => GMapKey (CEq c p q a) where
data GMap (CEq c p q a) v = GMapCon (GMap a v)
empty = GMapCon empty
lookup (C c) (GMapCon m) = lookup c m
insert (C c) v (GMapCon m) = GMapCon (insert c v m)
instance (GMapKey a) => GMapKey (Var a) where
data GMap (Var a) v = GMapVar (GMap a v)
empty = GMapVar empty
lookup (Var x) (GMapVar m) = lookup x m
insert (Var x) v (GMapVar m) = GMapVar (insert x v m)
instance (GMapKey a) => GMapKey (Rec a) where
data GMap (Rec a) v = GMapRec (GMap a v)
empty = GMapRec empty
lookup (Rec x) (GMapRec m) = lookup x m
insert (Rec x) v (GMapRec m) = GMapRec (insert x v m)
-- Boilerplate code, but unavoidable (for now)
instance GMapKey k => GMapKey [k] where
data GMap [k] v = GMapList (GMap (Rep [k]) v)
empty = GMapList empty
lookup k (GMapList m) = lookup (from k) m
insert k v (GMapList m) = GMapList (insert (from k) v m)
-- Example
t1 :: Maybe String
t1 = lookup [1,2,3] $ insert ([1..3] :: [Int]) "[1,2,3]" $ empty