Functors don’t work with data types that require specific types
haskell
Solution
The type of `fmap` is generic; you can't constrain it:
fmap :: Functor f => (a -> b) -> f a -> f b
Those `a`s and `b`s must be completely polymorphic (within the constraints of your `Functor` instance), or you don't have a `Functor`. The handwavy way of explaining why this is is because a `Functor` must obey some theoretical laws to make them play nice with Haskell's other data types:
fmap id = id
fmap (p . q) = (fmap p) . (fmap q)
If you have a data type that is parameterized over multiple types, i.e:
data Bar a b = Bar a b
You can write a `Functor` instance for `Bar a`:
instance Functor (Bar a) where
fmap f (Bar a b) = Bar a (f b)
You can also write a `Bifunctor` instance for `Bar`:
instance Bifunctor Foo where
first f (Bar a b) = Bar (f a) b
second f (Bar a b) = Bar a (f b)
...which again must follow some laws (listed on the linked page).
Edit:
You could write your own class to handle the type of behavior you're looking for, but it would look like this:
class FooFunctor f where
ffmap :: (String -> String) -> f -> f
But in this case, we'd have to make new entire classes for every single permutation of "inner types" we might have (like String), in order to cover all bases.
You can also write a class (call it `Endo`) that only permits endomorphisms (functions of type `a -> a`) on the "inner type" of a data type, like this:
class Endo f where
emap :: (a -> a) -> f a -> f a
Then, if you changed your data type a bit, and instantiated an appropriate instance of Endo, e.g.
data Foo' a = Foo' a
type Foo = Foo' String
instance Endo Foo' where
emap f (Foo a) = Foo (f a)
...if you write functions of type `Foo -> Foo`, you're guaranteed to preserve the "Stringiness" of the inner type you're mapping if you use `emap`. A quick search on hayoo reveals that this type of thing is relatively common practice, but doesn't really exist as a standard type class.
Problem
This works fine: ``` data Foo a = Foo a instance Functor Foo where fmap f (Foo s) = Foo (f s) ``` This throws an Error: ``` data Foo = Foo String instance Functor Foo where fmap f (Foo s) = Foo (f s) ``` Error: ``` Kind mis-match The first argument of `Functor' should have kind `* -> *', but `Foo' has kind `*' In the instance declaration for `Functor Foo' ``` What am I missing here? Why can’t I use functors to wrap and unwrap `Foo` if it holds a specific type? UPDATE I guess I can ask this another way: ``` data Foo = Foo String deriving(Show) let jack = Foo "Jack" -- Some functory thingy here putStrLn $ show $ tail <$> jack -- Foo "ack" ``` Why can't I do this? Or is there another construct for this use case?