derive-topdown-0.1.1.0: src/Data/Derive/TopDown/IsInstance.hs
-----------------------------------------------------------------------------
-- |
-- Module : Data.Derive.TopDown.IsInstance
-- Copyright : (c) Song Zhang
-- License : BSD-style (see the LICENSE file)
--
-- Maintainer : haskell.zhang.song `at` hotmail.com
-- Stability : experimental
-- Portability : non-portable
--
-----------------------------------------------------------------------------
module Data.Derive.TopDown.IsInstance
( isInstance'
) where
import Data.Derive.TopDown.Types
import Data.Generics
import GHC.Exts
{-
Note:
Since GHC template-haskell isInstance function cannot work with
polymorphic type. It cannot check whether @Eq a => [a]@ is an
instance of 'Eq', here
>poly_a :: Q Bool
>poly_a = do
> poly_a_t <- [t| forall a. Eq a => [a] |]
> isInstance ''Eq [poly_a_t]
> $(poly_a >>= stringE.show)
>"False"
>poly_a' :: Q Bool
>poly_a' = do
> poly_a_t <- [t| forall a. [a] |]
> isInstance ''Eq [poly_a_t]
> $(poly_a >>= stringE.show)
>"False"
So, here I change all the polymorphic types in the type into 'Any'
@type family Any :: k where {}@
See https://gitlab.haskell.org/ghc/ghc/-/issues/10607
-}
import Language.Haskell.TH
replace_poly_type :: Type -> Type
replace_poly_type (VarT _) = ConT ''Any
replace_poly_type x = x
replace_poly_type_trans :: Data a => a -> a
replace_poly_type_trans = everywhere (mkT replace_poly_type)
remove_explicit_forall :: Type -> Type
remove_explicit_forall (ForallT _ _ t) = t
remove_explicit_forall t = t
remove_explicit_forall_trans :: Type -> Type
remove_explicit_forall_trans = everywhere (mkT remove_explicit_forall)
isInstance' :: ClassName -> [Type] -> Q Bool
isInstance' cls tys =
let trans = remove_explicit_forall_trans . replace_poly_type_trans
in isInstance cls (map trans tys)