Skip to content

Instantly share code, notes, and snippets.

@ajnsit
Created November 12, 2020 05:44
Show Gist options
  • Save ajnsit/3945709347c95ce8c8a3ad950ddec116 to your computer and use it in GitHub Desktop.
Save ajnsit/3945709347c95ce8c8a3ad950ddec116 to your computer and use it in GitHub Desktop.
An example of an equality class that works across different types
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Eqq where
-- An example of an equality class that works across different types
-- The current implementation is needed to pointer compare different objects (even if of different types)
import Data.Proxy (Proxy (..))
import System.IO.Unsafe (unsafePerformIO)
import System.Mem.StableName (makeStableName)
-- It's possible to test for type equality using *closed* type families
-- Typeclasses are not able to do this
type family F a b :: Bool where
F a a = 'True
F _ _ = 'False
-- This is the desired class we want to implement
class Eqq a b where
eqq :: a -> b -> Bool
-- We define a decorated class which takes the equality information from the type level function
-- And then decides how to perform the equality operation
class Eqq' (flag :: Bool) a b where
eqq' :: Proxy flag -> a -> b -> Bool
-- Then we can dispatch automatically based on the type level function's result
instance (F a b ~ typesAreEq, Eqq' typesAreEq a b) => Eqq a b where
eqq = eqq' (Proxy :: Proxy typesAreEq)
-- Here's how to compare when the types are equal
instance Eqq' 'True a a where
eqq' _ a b = unsafePerformIO $ do
a1 <- makeStableName a
b1 <- makeStableName b
return (a1 == b1)
-- Here's how to compare when the types are not equal
-- Comparing unequal types always fails
instance Eqq' 'False a b where
eqq' _ _ _ = False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment