Defining your own Functor - haskell

I've been trying to understand what a Functor is in Haskell, and for that I've want an example of a Functor, without any other properties.
The working example I came up with was
data MyFunctor a b = MyFunctor a b deriving Show
instance Functor (MyFunctor a) where
fmap g (MyFunctor a b) = MyFunctor a $ g (b)
which I guess is a semi-practical Functor as the left value can be stored safely while the right value operated on. I then want to have the left value be replaced with the right value before the operation. So that...
Main> fmap (+2) MyFunctor 2 5
MyFunctor 5 7
Changing the instance declaration to do that however, yields an error.
data MyFunctor a b = MyFunctor a b deriving Show
instance Functor (MyFunctor a) where
fmap g (MyFunctor a b) = MyFunctor b $ g (b)
Which I don't understand, or know what to search to find a similar enough question to help me.
C:\Haskell\func.hs:3:28: error:
* Couldn't match type `a1' with `a'
`a1' is a rigid type variable bound by
the type signature for:
fmap :: forall a1 b. (a1 -> b) -> MyFunctor a a1 -> MyFunctor a b
at C:\Haskell\func.hs:3:3
`a' is a rigid type variable bound by
the instance declaration at C:\Haskell\func.hs:2:10
Expected type: MyFunctor a b
Actual type: MyFunctor a1 b
* In the expression: MyFunctor b $ g (b)
In an equation for `fmap':
fmap g (MyFunctor a b) = MyFunctor b $ g (b)
In the instance declaration for `Functor (MyFunctor a)'
* Relevant bindings include
b :: a1 (bound at C:\Haskell\func.hs:3:23)
a :: a (bound at C:\Haskell\func.hs:3:21)
g :: a1 -> b (bound at C:\Haskell\func.hs:3:8)
fmap :: (a1 -> b) -> MyFunctor a a1 -> MyFunctor a b
(bound at C:\Haskell\func.hs:3:3)

I then want to have the left value be replace with the right value before the operation.
This is an illegal thing for a Functor to do: GHC is correctly telling you that the types don't work out. In particular, the left part of your MyFunctor value may have a different type than the right part, as in MyFunctor 5 "hello". And since fmap must operate on only the last type parameter of your type, it must therefore leave the first part alone. Let's look at a more specific example.
Recall that the type of fmap is
fmap :: Functor f => (a -> b) -> f a -> f b
And suppose you have an object you'd like to fmap over:
obj :: MyFunctor Int String
What, then, must be the type of f to call fmap f obj? To unify the involved types, we must have
f :: (String -> a)
and
fmap f obj :: MyFunctor Int a
So you can see that it is impossible to "replace" the first, Int, field with the previous value of the second, String field: the only thing allowed in that place is what was there before, an Int!
Now, you might imagine that you could make the types work out if you changed your MyFunctor definition so that the two fields have the same type:
data MyFunctor a = MyFunctor a a
-- Also illegal
instance Functor MyFunctor where
fmap f (MyFunctor a b) = MyFunctor b (f b)
But you can't do this either, because b and f b may be of different types, and the caller gets to choose what f to use, so your implementation of fmap may not assume they are the same.
In fact, for any given data type, there is at most one legal definition of Functor: if you find one which is legal, you can be certain that any other definition is illegal: either the types won't match up, or it will break one of the two Functor laws:
fmap id == id
fmap f . fmap g == fmap (f . g)
How might you break one of these laws while still having the types line up? By operating on some piece of the structure that is not part of the structure being fmaped over. For example, often someone writes a (bad!) Functor like this:
data Counter a = Counter Int a
instance Functor Counter where
fmap f (Counter n x) = Counter (n + 1) (f x)
But this breaks both of the Functor laws, because it allows you to count how many times fmap has been called, which is supposed to be a detail which is not exposed.
fmap id (Counter 0 0) == Counter 1 0
(fmap tail . fmap tail) /= fmap (tail . tail)

First up, it's really good you're trying to understand this. It's one of the underpinnings of all the amazing things in Haskell.
Second up, I think there are better ways to understand Functor than trying to create an instance yourself. One of the best ways is to first up use fmap on as many existing Functor instances are you can find. There are already a bunch in the Prelude. Look at the source code of them to see how they're instantiated. This will give you an intuition for what they are.
The type you've "created" above is actually already in the prelude, for example. It's called (,). (Made a mistake of saying this was Either earlier - it's not, as that type is data Either a b = Left a | Right b sorry about that.)
What you want to do is get a feeling for the roughly ten Functors that are in Prelude first. But don't just get a feeling for the Functor part. Make sure you understand the underlying data type and structure. For this reason, this is going to be a bit of a futile exercise unless you truly understand types, algebraic data types (both sum and product), multi-parameter types and typeclasses (not how to use or instantiate typeclasses, just what they are, and how the mechanism works).
If you want a good intuitive introducion to using the basics of these things, I'd say work through the book I helped work on to do this: http://happylearnhaskelltutorial.com)
There is a big difference between using Functor instances, and creating them. I think you'll get a much better intuition of what they mean and are if you use a bunch of them. Only then, IMHO, should you approach instantiating one yourself. At that point, also, it's a good idea to look up the laws, because they matter. This should clear up any misconceptions you have of what they are or what they could be.
To put you on the path, though, they are about applying a function within the most shallow level of some structure. That structure is the structure of the type in question. So, in a List, it'll be all the "values within the list" (for want of a better way to describe lists), because if you look at the defined type of List, you'll see that that's actually the most shallow level of a list. To understand why, though, you need to really understand the type of lists in Haskell.
So, I would check out how the following types work as Functors: Maybe, List (aka []), Either, Data.Map, (->), (,). Data.Tree (rose trees), the Identity type in Control.Monad.Identity (just about the simplest parameterized algebraic data type you can have, it wraps its value: data Identity a = Identity a). Do a search for more (there are heaps!)
I wish you a happy time!

The error message is quite verbose, and tells the whole story.
First, it tells us that the type of fmap, in that instance should be
fmap :: forall a1 b. (a1 -> b) -> MyFunctor a a1 -> MyFunctor a b
Hence, if f is any function a1 -> b, we must make fmap f to have type MyFunctor a a1 -> MyFunctor a b.
Note how the return type is MyFunctor a b. Indeed, that's what GHC expected:
Expected type: MyFunctor a b
But instead it found something else:
Actual type: MyFunctor a1 b
How could that be? Well, fmap returns MyFunctor b (g b) and g b has type b (correct, as expected), but b (the value) has type a1, instead of the expected a.
More practically, fmap can only alter the b component in MyFunctor a b, it can not affect the a component. This can be seen from the type signature of fmap.

I don't think you can swap the values around like that. You've declared MyFunctor to contain two values of the generic types a and b. These are not necessarily of the same type. You could, for example, create a value like this:
MyFunctor "foo" 42
When you declare an instance of Functor (MyFunctor a), you've basically said that for any generic type a, you can map MyFunctor a b to MyFunctor a c.
For example, if a is String, as in the above example, you can map MyFunctor String b to MyFunctor String c if you have a function b -> c.
You can't swap the arguments, because the first value must retain its type.
It can't do that in the above example if c is any other type than String.

Related

Order of type-variables in instance-declarations

Suppose I have a type T a b and I want to write an instance declarations e.g. an instance declaration for Functor that ranges over a and not b. Is this possible without defining a newtype?
I read What is the rule of the order of multiple type variables in haskell? which leads me to believe that this is not possible, but this seems completely arbitrary to me.
What I'm hoping for is something like:
instance Functor (T * b)
It's not arbitrary. It's how Hindley-Milner type inference works with higher-kinded types and curried type constructor application. Unification of type variables is based on the concept of generative type constructors. That is, if (f a) ~ (g b), then f ~ g and a ~ b, where ~ is type equality.
Let's apply that to unification of an expression like (fmap f someT), for someT :: T a b. I'll start by giving everything other than someT fresh type variables, to work the way unification does.
someT :: T a b
fmap :: (c -> d) -> f c -> f d
f :: e
By the fact that fmap is provided f as a first argument, we unify (c -> d) ~ e. So..
fmap f :: f c -> f d
someT :: T a b
This is where generativity comes into it. From here, we see (f c) ~ (T a b). Let me add some additional parenthesis for clarity: (f c) ~ ((T a) b). This is how type constructors work in Haskell - they are curried in the same way as term-level functions. By generativity, f ~ (T a) and c ~ b.
Then from that:
fmap f someT :: T a d
So it's necessarily true that the Functor instance must operate only on the second type argument of the type T.
Of course this all goes back to the type inference algorithm. You could give up Hindley-Milner or curried type constructors to make things work differently. But the result would be very different from Haskell in far more ways than just allowing a couple instances that Haskell doesn't.

How to create functor instance for phantom type where first argument phantom?

One of the exercises in the http://haskellbook.com is to write a functor instance for
data EvilGoateeConst a b =
GoatyConst b
My attempt is
instance Functor (EvilGoateeConst a) where
fmap f (GoatyConst b) = GoatyConst b
The simplest fix is just to switch the arguments to the type constructor, but I guess that is verboten. What is the simplest way of fixing this without changing the original type?
(And I am not applying the function because that makes the compiler barf, but I think it still is a valid functor according to the laws.)
I think you are overthinking this problem - look at the type of fmap in this case it should be:
fmap :: (b -> c) -> EvilGoateeConst a b -> EvilGoateeConst a c
The reason is that EvilGoateeConst a b ~ (EvilGoateeConst a) b and so EvilGoateeConst a :: * -> * fits exactly the kind a Functor instance need to have but now the a is fixed and the functor might change the b instead
ok I don't know how to say more without totally spoiling it so don't look if you want to try it yourself but the answer is just:
instance Functor (EvilGoateeConst a) where
fmap f (GoatyConst b) = GoatyConst (f b)

Partially Applied Types in Haskell

Based on this question, in this code
data Promise a b = Pending (a -> b) | Resolved b | Broken
instance Functor (Promise x) where
fmap f (Pending g) = Pending (f . g)
IF
g :: a -> b
then
Pending g :: Promise a b
also
f :: b -> c
because of the existence of f . g.
That means
Pending (f . g) :: Promise a c`.
Wrapping up
fmap :: (b -> c) -> Promise a b -> Promise a c
Now fmap alone has this signature (adapted to the above)
fmap :: Functor f => (b -> c) -> f b -> f c
This only conforms if you assume that f = Promise a. While the end product seems reasonable, how do you interpret the type of f or equivalently what it the type of a partially applied promise Promise a?
At the type level you have another programming language, almost-Haskell. In particular, you can view types as having constructors and being able to be partially applied.
To view this a bit more rigorously, we introduce "types of types" called "kinds". For instance, the type constructor Int has kind
Int ::: *
where I write (:::) to read "has kind", though this isn't valid Haskell syntax. Now we also have "partially applied type constructors" like
Maybe ::: * -> *
which has a function type just like you'd expect at the value level.
There's one really important concept to the notion of kinds—values may instantiate types only if they are kind *. Or, for example, there exist no values of type Maybe
x :: Maybe
x = -- .... what!
In fact, it's not possible to even express a type of kind other than * anywhere where we'd expect that type to be describing a value.
This leads to a certain kind of restriction in the power of "type level functions" in Haskell in that we can't just universally pass around "unapplied type constructors" since they don't always make much sense. Instead, the whole system is designed such that only sensible types can ever be constructed.
But one place where these "higher kinded types" are allowed to be expressed is in typeclass definitions.
If we enable KindSignatures then we can write the kinds of our types directly. One place this shows up is in class definitions. Here's Show
class Show (a :: *) where
show :: a -> String
...
This is totally natural as the occurrences of the type a in the signatures of the methods of Show are of values.
But of course, as you've noted here, Functor is different. If we write out its kind signature we see why
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
This is a really novel kind of polymorphism, higher-kinded polymorphism, so it takes a minute to get your head all the way around it. What's important to note however is that f only appears in the methods of Functor being applied to some other types a and b. In particular, a class like this would be rejected
class Nope (f :: * -> *) where
nope :: f -> String
because we told the system that f has kind (* -> *) but we used it as though it could instantiate values, as though it were kind *.
Normally, we don't have to use KindSignatures because Haskell can infer the signatures directly. For instance, we could (and in fact do) write
class Functor f where
fmap :: (a -> b) -> f a -> f b
and Haskell infers that the kind of f must be (* -> *) because it appears applied to a and b. Likewise, we can fail "kind checking" in the same was as we fail type checking if we write something inconsistent. For instance
class NopeNope f where
fmap :: f -> f a -> a
implies that f has kind * and (* -> *) which is inconsistent.
You are only missing the equations for Resolved and Broken. The only reasonable implementation I can think of is
fmap f (Resolved x) = Resolved (f x)
fmap _ Broken = Broken
Other than that, your code is fine.
I wanted to add to #J. Abrahamson's fantastic answer. A lot of my understanding from Haskell's kind system is from this diogo castro's blog which I highly recommend.
Coming to the question of Partially Applied Types. Apart from type classes it's also possible to use them in type constructors. Taking an example from the blog.
data NonEmpty f a = MkNonEmpty { head :: a, tail :: f a }
:k NonEmpty
-- NonEmpty :: (* -> *) -> * -> *
:t MkNonEmpty { head = (3 :: Int), tail = Maybe 3 }
-- :: NonEmpty Maybe Int
This is an old question so this might be a recent addition to Haskell. It can be summarized as type constructors can take types and type constructors as arguments.

How does ghc know which definition of fmap, etc. to use?

I know that fmap has type (a -> b) -> f a -> f b where f is a functor (and does different things depending on what the functor is). My basic question is this: given some invocation fmap r x, how does ghc figure out what the functor f is, just given the types of x and r?
Let me make this more precise. Suppose f and f' are functors such that f a = f' a for some type a, but f b and f' b are different. If r has type a -> b and x has type f a, it seems there are two different possible results for fmap r x: something of type f b and something of type f' b. How is this ambiguity resolved?
A secondary question: I wanted to test this out by making a weird functor -- maybe something that takes a to [Int] for any type a and does something stupid to functions... but I apparently haven't found the right bit of syntax that allows me to specify functors this way. (Is there something like data Newtype a = [Int] that works? It seems I'd need to make a typeclass name before I can make it an instance of functor.)
EDIT: I get it now, but for the record, the real issue (which is only implicit in my question) was that I didn't realize you can't have a functor Foo such that Foo a is a type like Int that already exists.
I think the general answer you're looking for is that Haskell types are organized using "kinds", which are like types of types.
Here's the Functor class
class Functor f where
fmap :: (a -> b) -> f a -> f b
It's not explicit, but this means that f is a type constructor with kind * -> *. Only types with that kind can be made Functors.
This is actually a rather strong statement. It means that any Functor must be parametric in a type argument. Now consider your statement:
Suppose f and f' are functors such that f a = f' a for some type a,
but f b and f' b are different.
Given the kind system, this isn't possible. Since a Functor is parametric in its type argument, f a = f' a implies f = f', therefore f b = f' b.
I'm not entirely sure what you're asking for with the "weird functor", but it sounds like something that couldn't be expressed with the Functor type class. IIRC Functor can only express endofunctors on Hask; you may need a different abstraction that allows for functors between categories.
Haskell type classes are based on first-order logic resolution. A type class constraint on a type variable is a predicate (you may have seen error messages indicating this if you ever tried to use a type class name where a type name was required) in that logic system.
Haskell requires a unique solution for each (Predicate, Type) pair throughout the program, so you will not be able to create two different Functor instances over Int, for example. The standard way around this, such as in the Monoid class for numeric types that could provide either a summation or product depending on how you define the monoidal operator you want to use, is to provide newtype wrappers over the concrete type that you want the class to have different instances for.
So, for Monoid, we have newtype Sum a = Sum { getSum :: a } and instance Num a => Monoid (Sum a) for the sum monoid and newtype Product a = Product { getProduct :: a } and instance Num a => Monoid (Product a) for the product monoid.
Note that since type only creates an alias for a type, it's not sufficient to provide multiple class instances for a type. The newtype declaration is like type in the sense that it does not produce any additional run-time structure for the new type, but it is unlike type in that it creates a new type rather than a type alias.
It depends on what argument you pass it. For example a list is a functor and so is Maybe
main = do
putStrLn $ show (double [1..5])
putStrLn $ show (double (Just 3))
putStrLn $ show (double Nothing)
double :: (Functor f, Num a) => f a -> f a
double = fmap (*2)
*Main> main
[2,4,6,8,10]
Just 6
Nothing
This double function will work for any functor that is holding an Num.
"Suppose f and f' are functors such that f a = f' a for some type a, but f b and f' b are different."
This doesn't really make sense. Either f and f' are the same, or they aren't. You seem to be suggesting some kind of in-between state where it varies depending on the argument type; that can't happen.
"If r has type a -> b and x has type f a, it seems there are two different possible results for fmap r x: something of type f b and something of type f' b. How is this ambiguity resolved?"
Where did f' come from? Nothing in the above signatures mentions it. Since x has type f a, it follows that the result of fmap must have some type beginning with f - in this case f b, since r :: a -> b. This is perfectly unambiguous. The result of fmap is always in the same functor as you started with.

Let Haskell functors sink in.

Learn You a Haskell has an example about functors. I can read LYAH, and text, and figure out what is supposed to happen -- but I don't know enough to write something like this. I'm finding this problem often in Haskell.
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
However, I'm confused.. Why doesn't this comple
instance Functor (Either a) where
fmap f (Right x) = Right (x)
fmap f (Left x) = Left (f x)
If f isn't being used in the top definition, then what else constrains x such that it can't satisfy Left
Here's the functor class:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Note that "f" by itself is a type constructor because it's applied to a type variable in the fmap line. Here are some examples to make this clear:
Type constructors:
IO
Maybe
Either String
Types:
IO Char
Maybe a
Either String String
"Maybe a" is a type with one type constructor (the "Maybe") and one type variable (the "a"). It's not something concrete yet, but it is usable in type signatures for polymorphic functions.
"Either" is a type constructor that takes two type arguments, so even after you apply one (e.g. Either String it's still a type constructor because it can take another type argument.
The point of this is: when you define a Functor instance, the type constructor f cannot change. This is because it's represented by the same variable, f, as both the argument and result of fmap. The only type that's allowed to change is the type that's applied to the f constructor.
When you write instance Functor (Either c), Either c is filled in for f everywhere in the declaration of fmap. This gives fmap the following type for this instance:
fmap :: (a -> b) -> (Either c) a -> (Either c) b
With the definition of Either, the only useful way to get this type is by applying the Right value to the function. Remember that "Either" has two possible values with possibly different types. Here the Left value has type 'c', so you can't apply it to the function (which expects an 'a')[1], and the result also wouldn't be correct because you'd be left with Either b a, which doesn't match the class definition.
After replacing "f" with "Either c" to get the above type signature for fmap with the "Either c" instance, writing the implementation is next. There are two cases to consider, the Left and the Right. The type signature tells us that the type of the Left side, "c", can't change. We also don't have any way to change the value because we don't know what type it actually is. All we can do is leave it alone:
fmap f (Left rval) = Left rval
For the Right side, the type signature says that we have to change from a value with type "a" to a value with type "b". The first argument is a function to do exactly that, so we use the function with the input value to get the new output. Putting the two together gives the full definition
instance Functor (Either c) where
fmap f (Right rval) = Right (f rval)
fmap f (Left lval) = Left lval
There's a more general principle at work here which is why writing a Functor instance that adjusts the Left side is impossible, at least with the Prelude definitions. Copying some code from above:
class Functor f where
fmap :: (a -> b) -> f a -> f b
instance Functor (Either c) where ...
Even though we have a type variable 'c' in the instance definition, we can't use it in any of the class methods because it's not mentioned in the class definition. So you can't write
leftMap :: (c -> d) -> Either c a -> Either d a
leftMap mapfunc (Left x) = Left (mapfunc x)
leftMap mapfunc (Right x) = Right x
instance Functor (Either c) where
--fmap :: (c -> d) -> Either c a -> Either d a
fmap = leftMap
The result of leftMap, and thus fmap, is now (Either d) a. The (Either c) has changed to an (Either d), but this isn't allowed because there's no way to express it in the Functor class. To express this, you'd need a class with two type variables, e.g.
class BiFunctor f where
lMap :: (a -> b) -> f a c -> f b c
rMap :: (c -> d) -> f a c -> f a d
biMap :: (a -> b) -> (c -> d) -> f a c -> f b d
In this class, since both the left and right type variables are in scope, it's possible to write methods that operate on either (or both) sides.
instance BiFunctor Either where
lMap = leftMap
rMap = rightMap --the same as the standard fmap definition
biMap fl fr e = rMap fr (lMap fl e)
Although in practice people usually just write "biMap" for the BiFunctor class and use "id" for the other function if a left or right mapping is necessary.
[1] More accurately, the Left value has type 'c', the function expects an 'a', but the type checker can't unify those types because the 'c' type isn't in scope in the class definition.
Left and Right aren't types, and Left x and Right y are of the same type. They are just constructors of Either. You may consider
Left :: c -> Either c d
Right :: d -> Either c d
You can have 2 fmap declarations because we know the Left's and the Right's are different values. It's just like
g :: Int -> Int
g 1 = 2
g 2 = 4
g n = n
Here we can't say 1 and 2 and n are different "types" just because pattern matching works.
The Functor class is defined such that
class Functor f where
fmap :: (a -> b) -> f a -> f b
Note that a and b are arbitrary types. For clarity, let's rename the a in your instance to c, and the function f to func.
instance Functor (Either c) where
fmap func (Right x) = Right (x)
fmap func (Left x) = Left (func x)
Assume your Either follows the default definition
data Either c d = Left c | Right d
then by your definition,
fmap func (Right x) = Right x
-- # (a -> b) -> f a f b
-- # f = Either c
this forces a = b, and
fmap func (Left x) = Left (func x)
-- # (a -> b) -> f a f b
-- # f = Either c
forces c = a = b. Both are not valid considering a, b and c are independent arbitrary types.
Ok so here's another very simple try at this.
You ask why this doesn't compile:
instance Functor (Either a) where
fmap f (Right x) = Right (x)
fmap f (Left x) = Left (f x)
So let's try to simplify the problem by trying to define the same function without putting it as part of a class instance declaration:
That gives us
foo f (Right x) = Right (x)
foo f (Left x) = Left (f x)
Which indeed does compile. ghci tells us the type signature:
*Main> :t foo
foo :: (t1 -> a) -> Either t1 t -> Either a t
We'll rename some of the variables to get something more uniform looking:
foo :: (a -> b) -> Either a c -> Either b c
That makes perfect sense. It takes a function and applies it to the Left of an Either.
But what's the signature for fmap?
*Main> :t fmap
fmap :: (Functor f) => (a -> b) -> f a -> f b
So let's substitute Either c for f in the fmap signature (I renamed Either a to Either c to keep our two different as from getting mixed up):
fmap :: (a -> b) -> Either c a -> Either c b
Do you see the problem? Your function is perfectly valid -- it just has a different type than what fmap for Either a must necessarily have.
This is a sort of beautiful thing about types. Given the signature for fmap, there is really only one meaningful implementation for fmap on Either a.
Sometimes, when we're lucky and careful, we can end up in similar situations -- given a type signature, the function almost writes itself.
Edit: trying to answer the questions below.
1) There's no "composition of two functions" going on. To get the type signature for fmap over Either a just go through the fmap function signature, and every place you see f, replace it with Either a. We would call that a "specialization" of the type signature of fmap. Which is to say, it is strictly less general than the normal type of fmap -- anyplace that requires a function of the more specialized type, you can pass in something of the general type with no problems.
2) Your function for mapping over the left side (which I named "foo" in the above examples) is just fine. It works fine, it does what you want. You just can't name it fmap and use it in a Functor instance. Personally, I'd name it something like onLeft or mapLeft.
All the following can be ignored/is for information, but not a suggestion for future reading in the near future/actual use:
If one wants to get very technical, because you can map over both the left and the right side (although you can only declare Functor for the latter), Either is not only a Functor, but a Bifunctor. This is provided in, e.g., ekmett's Category-Extras library ( see http://hackage.haskell.org/packages/archive/category-extras/0.44.4/doc/html/Control-Bifunctor.html).
There's lots of cool stuff involving calculating with programs, and "origami programming" that uses bifunctors more rigorously. You can read about it here: http://lambda-the-ultimate.org/node/1360. But, you probably don't want to, at least until you're much more familiar with Haskell. It is computer-sciency, mathy, researchy, and very cool, but not necessary at all to understand idiomatic Haskell programming.
While I will eventually cleave to your format, I'm going to start with something in a slightly different format, as I think it will make my explanation clearer.
Let's consider a different datatype
data Choice a = Default Integer | Chosen a
-- This corresponds to your top, working, instance.
instance Functor Choice where
fmap f (Default i) = Default i
fmap f (Chosen a) = Chosen (f a)
It should be clear why this instance works. However, what about the following:
-- Broken!
instance Functor Choice where
fmap f (Default i) = Default (f i)
fmap f (Chosen a) = Chosen a
You should be able to see why this doesn't work. The type of fmap is Functor f => (a -> b) -> f a -> f b; in this context, it's (a -> b) -> Choice a -> Choice b. Thus, the f argument has the type a -> b. However, in the second (failed) instance declaration, you write f i. We know, because of the datatype declaration, that i must be an Integer, so we can't apply f to it. Similarly, since a has type a, Chosen a will have type Chosen a, not type Chosen b. Thus, the Functor instance on the bottom can't work.
Well, your top instance for Either works because, like in the Choice example, it obeys the types. Let's look at it, with a few renamings:
instance Functor (Either c) where
fmap f (Left c) = Left c
fmap f (Right a) = Right (f a)
This instance declaration doesn't declare an instance of Functor for Either—it can't. Something which is an instance of Functor must take one type parameter. Thus, Int can't be a functor, since Int takes no type parameters, but [] and Maybe can be, since [a] and Maybe a are complete types. Either, however, takes two type parameters: Either a b. Thus, what this instance does is declare that Either c is a functor for any possible c. That c is fixed for the duration of the instance declaration. So let's go through and add types (this is not legal syntax!):
instance Functor (Either c) where
fmap :: forall a b. (a -> b) -> (Either c) a -> (Either c) b
fmap f (Left (c :: c)) = Left c
fmap f (Right (a :: a)) = Right (f a :: b)
Since f has type a -> b, but c's type is fixed at c, we can't possibly write Left (f c); and even if we could, we want the c to be left alone, so that we can return an (Either c) b. Similarly, we must apply f to a in order to get something of type b.
This is also why your bottom instance doesn't work: you have a function which needs to work for any type being applied only to the fixed type c, and you leave the type you need to transform alone. Let's look at it, again with type signatures added:
instance Functor (Either c) where
fmap :: forall a b. (a -> b) -> (Either c) a -> (Either c) b
fmap f (Left (c :: c)) = Left (f c)
fmap f (Right (a :: a)) = Right a
Here, your first part of the function definition attempts to apply a function f :: a -> b to something of the fixed type c, which cannot work, so this already fails. But let's look at what type this generates. In this case, we'd expect that (somehow) f c would have the type b, and a would have the type a. In that case, we're returning a value of type Either b a, which is still not allowed.
Basically, the problem stems from this. First, note that f is the same in between the two function definition clauses, so it can't change between lines. Second, note that we are fixing c, and declaring an instance for that c. This is true for any c, but we only look at one at a time. Finally, because of this, Left's argument is not parametrized by the type that f expects; it's guaranteed to have some fixed type c. This means that (a) you can't apply f to it, and (b) you must apply it to Right's argument, since otherwise you won't change the type you're expected to change.
(Edit to try to answer the question better)
The definition of Either is:
data Either a b = Left a | Right b
So "Either" takes two type arguments. By the way, technically "Either" is not actually a type but a type constructor; it takes type arguments to create a type.
The definition of Functor is:
class Functor f where
fmap :: (p -> q) -> f p -> f q
So in this class definition any type "f" that is an instance of Functor must take a type argument. This isn't declared; it is inferred from the "f p" and "f q"; since "f" is being given a type parameter here it must be a type that takes one.
(Note: the original definition used "a" and "b" instead of "p" and "q". I'm using different letters to keep things distinct from "Either a b" when I get to that later)
In most cases "f" is a container type like a list or a tree. So for instance you have
data Tree a = ...
instance Functor Tree where
fmap func_a2b tree_of_a = ... -- tree of b.
However "Either" takes two type parameters, so how can we fit it into this scheme? The answer is that types can have partial application just like functions. In the same way as
I can declare a function
foo x y = ...
and then say "foo 2" in order to get a new function that expects the second argument, so I can say "Either a" to get a new type that expects the second type argument.
Now look at the original instance:
instance Functor (Either a) where ....
So here "Either a" is a type constructor that expects one more argument, just like Functor expects of its instances. So the type of "fmap" for "Either a" will be
fmap :: (p -> q) -> Either a p -> Either a q
So now in the "where" clause you have to give a definition of "fmap" that has this type. The first one you quote has this type because the second type parameter is used for the "Right" constructor, and that is the one that the function is applied to. The second one won't work, because it would have the type
fmap :: (p -> q) -> Either p a -> Either q a
And that is not what the Functor class says its going to be.
Belive it or not, this isn't magic. It all has to do with the type Either a b not being the same type as Either b a. Here is the definition of Either from Prelude
data Either a b = Left a | Right b
... Notice How the type variable a comes first, then b, and also notice that we only include a in the declaration of the Either Functor:
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
Now lets look at the definition of the Maybe Functor
instance Functor Maybe where
fmap = map
Here there is no type variable, Although Maybe takes one type parameter (like Maybe Int). What I am trying to get to is that types aren't functors, type constructors are functors (functors have kind *->*).
So let f :: b -> c, in the version of the Either Functor that works, the x from (Left x) is of type a, which is fine since it's (Either a) that is a functor, the x in (Right x) is of Type b so (Right x) is of type ((Either a) b), and (Right (f x)) is of type ((Either a) c), therefore fmap is of type (b->c) -> ((Either a) b) -> ((Either a) c), as required.
In your version that failed, we have that x in (Right (x)) is not of type a, but of type b, So (Right (x)) is not of type ((Either a) c) which doesn't fit with the type of fmap.
so to sum it up: the fmap that works comes out : (b -> c) -> (Either a) b -> (Either a) c,
but the one that doesn't work comes out: (b -> c) -> (Either b) a -> (Either c) a and thats not the right type for fmap.
Hopefully, this will help...
First, though, some background:
1) Functor needs a "type constructor", a (well, not a type per se,...) type that "needs" another regular type given to it to form a "full type", just like a generic in Java/C++.
So, for example, List is a Functor (it is, by the way), or Array, because (among other things) the full type isn't just List, but List<A>. So, :
A Functor takes a "type constructor", an incomplete type.
2) Either is a constructor type that Haskell folks (read: Edward Kmett, and other well-math-endowed all-stars) call a bifunctor. It needs two types given to it to be complete. For example, a full use of Either is: Either Integer String which means (yeah, yeah, "duh!") it's either a (Left) Integer, or a (Right) String. So, this means Either Integer is an incomplete type that is either a Left Integer or a Right...b when you
decide what that "b" is supposed to be.
Now, for the fun part!
The top stuff works because, fmap uses some type constructor, and uses it with an a -> b function to make a similar function from f a to f b - the hands-down favorite example for this in Haskell is the one for lists, AKA map :: (a -> b) -> ([a] -> [b]), where the Functor is the [ ] part. Now, using something like Either a (let's go ahead and use Either Integer from earlier), fmap's type signature looks like this:
fmap :: (a -> b) -> (Either Integer a -> Either Integer b)
and the two examples (from the Top part) show what fmap does with representative values of that Either Integer a type, in order to get an Either Integer b-typed value.
Now, yours -bottom- doesn't work, because:
You have a function, f, that takes
as to bs.
Your Left type has to be type
Integer, and stay an Integer (or
type Float, and stay a Float, what
ever type is the left one of the
two types of the Either type
you're using).
Your Right type has to be of
whatever type that the function
takes ("a"), and go to the type
that the function makes ("b").
It has to do this (but your stuff doesn't - that's why it doesn't work), because that's the type that fmap needs to have. Specifically, you have these equations:
fmap f (Right x) = Right (x)
fmap f (Left x) = Left (f x)
Your equations give fmap the types:
fmap :: (a -> b) -> Either c d -> Either c d
fmap :: (a -> b) -> Either a d -> Either b d
which not only doesn't fit what fmap wants, but it isn't even consistent with each other!
I'm sorry I wrote half a book to wade through, but I hope that gives some insight to you.
Top works because fmap::(b -> c) -> Either a b -> Either a c and yours -bottom- doesn't work because that would require fmap::(a -> c) -> Either a b -> Either a c. But, it would work if you changed Either to
data Either' a b = Left' b | Right' a deriving (Eq, Show)
instance Functor (Either' a) where
fmap f (Right' x) = Right' (x)
fmap f (Left' x) = Left' (f x)
The instance you're trying to write, let's call it fmap2 for now, has the following type:
fmap2 :: (a -> b) -> Either a c -> Either b c
If you set the LANGUAGE pragma TypeOperators, GHC also accepts the type
fmap2 :: (a -> b) -> (a `Either` c) -> (b `Either` c)
In an ideal world this also would work:
fmap2 :: (a -> b) -> (`Either` c) a -> (`Either` c) b
which would give a Functor instance for (`Either` c) but the similarity between normal operators (and their sections) and type operators breaks down at this point (unless there's a GHC option I'm missing!)
In short: your understanding of functors is okay, but you're bitten by the lack of type-level lambdas.
Ehm... How about a few words about "kinds" ?..
That may simplify understanding, I guess.
Remember what is currying. I.e. in ghci:
Prelude> let f x y z = x + y * z
f :: (Num a) => a -> a -> a -> a
Prelude> :t f 1
f 1 :: (Num t) => t -> t -> t
Prelude> :t f 1 2
f 1 2 :: (Num t) => t -> t
Prelude> :t f 1 2 3
f 1 2 3 :: (Num t) => t
The same things you have with types. When you say Either kind of that type is * -> * -> * (i.e. it takes two types and produces type) and when you say Either a kind is * -> * and for Either a b it's * (btw Monad a and Functor a requires a to be of kind * -> *, as I remember).
So when you say type Either a that means type that is still incomplete (requires some "argument" to be bound), so fmap :: (a -> b) -> f a -> f b becomes fmap :: (a -> b) -> (Either c) a -> (Either c) b when f substituted by Either c.

Resources