Skip to content

Instantly share code, notes, and snippets.

@aavogt
Created March 23, 2016 20:09
Show Gist options
  • Select an option

  • Save aavogt/d060d45345284a3e3239 to your computer and use it in GitHub Desktop.

Select an option

Save aavogt/d060d45345284a3e3239 to your computer and use it in GitHub Desktop.
overload Map and Set insert
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- | properly overload M.insert and S.insert
module Insert where
import Data.Proxy
import Data.Set (Set)
import qualified Data.Set as S
import Data.Map (Map)
import qualified Data.Map as M
class Insert1 e where
insert1 :: e
instance Ord e => Insert1 (e -> Set e -> Set e) where
insert1 = S.insert
instance Ord k => Insert1 (k -> v -> Map k v -> Map k v) where
insert1 = M.insert
-- a better way:
class Insert2 pk e where
insert2_ :: Proxy pk -> e -- user calls 'insert2'
type family MkPK x :: *
type instance MkPK (Set e) = Proxy Set
type instance MkPK (Map k v) = Proxy Map
instance (insertSet ~ (e -> Set e -> Set e), Ord e)
=> Insert2 (Proxy Set) insertSet where
insert2_ _ = S.insert
instance (insertMap ~ (k -> v -> Map k v -> Map k v), Ord k)
=> Insert2 (Proxy Map) insertMap where
insert2_ _ = M.insert
-- | figure out what collection we have
type family GetPK e
type instance GetPK (a -> b -> Set c) = Proxy Set
-- c could be `Map a (Set b) -> Map a (Set b)`, which
-- should make the result type Proxy Map. IE.
--
-- > insert () S.empty M.empty :: Map () (Set t)
-- type instance GetPK (a -> Set b -> c) = Proxy Set
type instance GetPK (a -> b -> Map c d -> e) = Proxy Map
type instance GetPK (a -> b -> c -> Map d e) = Proxy Map
insert2 :: forall t a b c. (Insert2 (GetPK t) t, t ~ (a -> b -> c)) => t
insert2 = insert2_ (Proxy :: Proxy (GetPK t))
{- ^
>>> :t \k -> (insert2 k mempty :: Set ())
\k -> (insert2 k mempty :: Set ()) :: () -> Set ()
compare with
>>> :t \k -> insert1 k mempty :: Set ()
\k -> insert1 k mempty :: Set ()
:: (Monoid a, Insert1 (t -> a -> Set ())) => t -> Set ()
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment