content: {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE RecordWildCards #-}
  {-# LANGUAGE TypeSynonymInstances #-}
  {-# LANGUAGE FlexibleInstances #-}
  
  -- from https://ocharles.org.uk/blog/guest-posts/2014-12-19-existential-quantification.html
  
  data HashMap k v = HM  -- ... -- actual implementation
  
  class Hashable v where
    h :: v -> Int
  
  data HashMapM hm = HashMapM
    { empty  :: forall k v . hm k v
    , lookup :: Hashable k => k -> hm k v -> Maybe v
    , insert :: Hashable k => k -> v -> hm k v -> hm k v
    , union  :: Hashable k => hm k v -> hm k v -> hm k v
    }
  
  
  data HashMapE = forall hm . HashMapE (HashMapM hm)
  
  -- public
  mkHashMapE :: Int -> HashMapE
  mkHashMapE = HashMapE . mkHashMapM
  
  -- private
  mkHashMapM :: Int -> HashMapM HashMap
  mkHashMapM salt = HashMapM { {- implementation -} }
  
  instance Hashable String where
  
  type Name = String
  data Gift = G String
  
  giraffe :: Gift
  giraffe = G "giraffe"
  
  addGift :: HashMapM hm -> hm Name Gift -> hm Name Gift
  addGift mod gifts =
    let
      HashMapM{..} = mod
    in
      insert "Ollie" giraffe gifts
  
  -- -------------------------------
  
  santa'sSecretSalt = undefined
  sendGiftToOllie = undefined
  traverse_ = undefined
  
  sendGifts =
    case mkHashMapE santa'sSecretSalt of
      HashMapE (mod@HashMapM{..}) ->
        let
          gifts = addGift mod empty
        in
          traverse_ sendGiftToOllie $ lookup "Ollie" gifts
  