Newtypes are often used to change the behavior of certain types when used in certain class contexts. For example, one would use the Data.Monoid.All
wrapper to change the behavior of Bool
when used as a Monoid
.
I'm currently writing such a newtype wrapper that would apply to a large range of different types. The wrapper is supposed to change the behavior of one specific class instance. It might look like this:
newtype Wrapper a = Wrapper a
instance Special a => Special (Wrapper a) where
-- ...
However, adding this wrapper will often change the usability of the wrapped type. For example, if I previously was able to use the function mconcat :: Monoid a => [a] -> a
, I am not able to now use it for a list of wrapped values.
I can of course use -XGeneralizedNewtypeDeriving
and newtype Wrapper a = Wrapper a deriving (Monoid)
. However, this only solves the problem for Monoid
and no other class, while I will be dealing with an open world full of different classes, and standalone orphan generalized newtype deriving is not really a practical option. Ideally, I'd like to write deriving hiding (Special)
(deriving every class except Special
), but that's not valid Haskell, of course.
Is there some way of doing this or am I just screwed and need to add a GHC feature request?
Look, GeneralizedNewtypeDeriving
is unsafe. In that vein, here is an unsafe way of doing it
{-# LANGUAGE GADTs, ConstraintKinds #-}
import Data.Monoid
import Unsafe.Coerce
data Dict c where
Dict :: c => Dict c
newtype Wrapper a = Wrapper a
addDictWrapper :: Dict (f a) -> Dict (f (Wrapper a))
addDictWrapper = unsafeCoerce
you can then use it anytime you need the typeclass instance
intWrapperNum :: Dict (Num (Wrapper Int))
intWrapperNum = addDictWrapper Dict
two :: Wrapper Int
two = case intWrapperNum of
Dict -> 1 + 1
this system of passing around explicit dictionaries is highly general, and has a pretty good (although experimental) library to support it called Data.Constraint
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With