Search code examples
haskellsyntaxtypeclassderivingderivingvia

Is there syntax for creating [Maybe a] analog, but of kind (* -> *)


I was trying to create an fmap that works on [Maybe a]. However, Maybe a has kind *, and fmap demands kind * -> *. This leads to the following unfortunate solution:

newtype Unfortunate a = Unfortunate ([Maybe a]) deriving Show

instance Functor Unfortunate
    where fmap f (Unfortunate a) = Unfortunate $ (fmap (fmap f)) a


-- |
-- >>> l = Unfortunate [Just 10, Just 1, Nothing, Just 15]
-- >>> fmap (*5) l
-- Unfortunate [Just 50,Just 5,Nothing,Just 75]

What is unfortunate is having to create a newtype at all. I'd expect it to be possible to create an instance that works for [Maybe a], for any a. I.e, something that can be called as fmap f [Just 10, Nothing].

I seem to be missing some piece of syntax. Is it possible to define such an instance?


Solution

  • What is unfortunate is the creation of the newtype. I'd expect it to be possible to create an instance that works for [Maybe a], for any a.

    There is already such an instance. It works, not only for any [Maybe a], but for any [a]. And since a can be unified with Maybe a, you can use it for [Maybe a] as well.

    Now, clearly this is not actually what you meant. When specialized to this type, fmap has type

    (Maybe a -> Maybe b) -> [Maybe a] -> [Maybe b]
    

    but you wish it took a function of type (a -> b) instead. I bring this up to explain why the use of a separate type cannot be avoided1. There is already an instance for the types you want, and so you cannot just define a new instance that replaces that behavior. You need a different type to attach that instance to.

    As discussed in another answer, there are generic types already defined that can be composed to get the setup you want. But you can't just use a bare [Maybe a].


    1 There are some language extensions you could turn on to break the type system to allow this, but this can have surprising consequences, and I won't go into that here.