Say we have a data type defined as
data A a = A' a deriving Show
We have
A :: * -> *
We can then make A an instance of Functor
:
instance Functor A where fmap f (A' x) = A' (f x)
This allows us to make a value of type A
and use fmap
to apply a function to the wrapped value
Prelude> let x = A' 1
Prelude> fmap (+1) x
A' 2
Now, if we defined A
as
data A = A' Int deriving Show
The kind of A
is
A :: *
Consequently, we can not make A
an instance of Functor -
instance Functor A where fmap f (A' x) = A' (f x)
<interactive>:4:18:
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `A' has kind `*'
In the instance declaration for `Functor A'
My question is, is there a generic way to apply a function to the wrap value for data types of kind *
with a data constructor that only takes one parameter (i.e., something analogous to fmap
)? It's fairly easy to write custom function:
Prelude> let myFmap f (A' x) = A' (f x)
Prelude> let x = A' 1
Prelude> myFmap (+1) x
A' 2
It's also possible to make A
an instance of Num
:
instance Num A where (+) (A' x) (A' y) = A' (x + y) -- Ignoring the warnings
Prelude> A' 1 + A' 1
A' 2
Both of these approaches work but is there a better way that I am missing?
I don't think there's a good generic solution for the second half of the question, but I can at least answer the first half.
This is the purpose of the mono-traversable package, which provides a MonoFunctor
typeclass. The instance for A'
would be:
type instance Element A' = Int
instance MonoFunctor a' where
omap f (A' i) = A' (f i)
YMMV on how useful this is versus a simple a'map :: (Int -> Int) -> A' -> A'
function or a lens.
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