{-# LANGUAGE DeriveGeneric #-}
import Data.Hashable
import Data.Hashable.Lifted
import GHC.Generics (Generic)

data Foo
  = Foo1 Int Char Bool
  | Foo2 String ()
  deriving (Eq, Generic)

instance Hashable Foo

data Bar = Bar Double Float
  deriving (Eq, Generic)

instance Hashable Bar

-- printHash :: (Hashable a, Show a) => a -> IO ()
-- printHash = print . hash

main :: IO ()
main = do
  putStrLn "Hashing Foo1"
  print . hash $ Foo1 22 'y' True
  putStrLn "Hashing Foo2"
  print . hash $ Foo2 "hello" ()
  putStrLn "Hashing Bar"
  print . hash $ Bar 55.50 9.125

-----------------------------------
-- Higher Rank Hashable Examples --
-----------------------------------

{- TODO:

newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }
data Free f a = Pure a | Free (f (Free f a))

instance (Hashable w, Hashable1 m) => Hashable1 (WriterT w m) where
    liftHashWithSalt h s (WriterT m) =
        liftHashWithSalt (liftHashWithSalt2 h hashWithSalt) s m
instance Hashable1 f => Hashable1 (Free f) where
    liftHashWithSalt h = go where
        go s x = case x of
            Pure a -> h s a
            Free p -> liftHashWithSalt go s p

instance (Hashable w, Hashable1 m, Hashable a) => Hashable (WriterT w m a) where
    hashWithSalt = hashWithSalt1
instance (Hashable1 f, Hashable a) => Hashable (Free f a) where
    hashWithSalt = hashWithSalt1
-}
