I've got the following data type:
data Users id height weight = User id height weight
instance Functor Users where
fmap f (User id height weight) = User(f id height weight)
Yet this won't compile?
It works fine when I use a type with a single parameter, such as:
data Users id = User id
instance Functor Users where
fmap f (User id) = User (f id)
Why isn't my first example working?
Each type and type constructor has a kind. Something simple like Int
has kind *
. Your single-argument type constructor Users
has kind * -> *
; it takes one type and returns a new one. Your first example of Users
has kind * -> * -> * -> *
; it takes three types and returns a new one.
Functor
only works with type constructors of kind * -> *
. This allows you to define a Functor
instance for your second Users
type constructor, but not your first one.
Think about your first try: the data constructor Users
takes three arguments, but your definition of fmap
attempts to call it with just one, the return value of f. You could make Users
a functor as long as you are willing to make all three fields the same type:
data Users a = Users a a a
instance Functor Users where
fmap f (Users a b c) = Users (f a) (f b) (f c)
In theory, you could define a class Trifunctor
(there is a Bifunctor
class available):
class Trifunctor f where
trimap :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> f a1 a2 a3 -> f b1 b2 b3
data Users a b c = Users a b c
instance Trifunctor Users where
trimap f g h (Users a b c) = Users (f a) (g b) (h c)
but it's debatable how useful this would be. Functor
is useful for general purpose containers, because they have a wide range of uses. Users
, on the other hand, seems pretty specific. You generally don't need the flexibility you are defining it with; data User = User Int Int Int
seems like it would work fine, and there is no need to map a function over this: how often to you need the same function to modify height, weight, and age in the same way?