Generic defaulting in Haskell - haskell

Given two functions:
f :: (A a, B b) => a -> b
g :: (B b, C c) => b -> c
Is there any way (in GHC) I can make it possible to write:
h x = g (f x)
Without having to add a type signature for f x, e.g.
h x = g ((f x) :: T)
By having some "default type" that f x takes if none is specified?
I suspect I need something like Defaulting in Haskell Prime but has this been implemented in GHC (or in GHC head)?

Stupid non-answer:
asT :: T -> T
asT = id
h = g . asT . f
Lack of "defaulting" is one of the pains of Haskell's flavor of generics. Things get too generic and Haskell doesn't know which instance to pick. The status quo is that "the programmer needs to explicitly resolve ambiguity." Rather than specifying top-level rules for defaulting, you just have to select the appropriate instance on a case-by-case basis. Num defaulting is a hacky exception to this rule.
The proposal you linked has a good example of why choosing defaults isn't trivial when multiple classes are involved.
default A (Int, String, ())
default B (String, Int, ())
(A t, B t) => t -- defaults to what?

Related

Is having a `(a -> b) -> b` equivalent to having an `a`?

In a pure functional language, the only thing you can do with a value is apply a function to it.
In other words, if you want to do anything interesting with a value of type a you need a function (for example) with type f :: a -> b and then apply it. If someone hands you (flip apply) a with type (a -> b) -> b, is that a suitable replacement for a?
And what would you call something with type (a -> b) -> b? Seeing as it appears to be a stand-in for an a, I'd be tempted to call it a proxy, or something from http://www.thesaurus.com/browse/proxy.
luqui's answer is excellent but I'm going to offer another explanation of forall b. (a -> b) -> b === a for a couple reasons: First, because I think the generalization to Codensity is a bit overenthusiastic. And second, because it's an opportunity to tie a bunch of interesting things together. Onwards!
z5h's Magic Box
Imagine that someone flipped a coin and then put it in a magic box. You can't see inside the box but if you choose a type b and pass the box a function with the type Bool -> b, the box will spit out a b. What can we learn about this box without looking inside it? Can we learn what the state of the coin is? Can we learn what mechanism the box uses to produce the b? As it turns out, we can do both.
We can define the box as a rank 2 function of type Box Bool where
type Box a = forall b. (a -> b) -> b
(Here, the rank 2 type means that the box maker chooses a and the box user chooses b.)
We put the a in the box and then we close the box, creating... a closure.
-- Put the a in the box.
box :: a -> Box a
box a f = f a
For example, box True. Partial application is just a clever way to create closures!
Now, is the coin heads or tails? Since I, the box user, am allowed to choose b, I can choose Bool and pass in a function Bool -> Bool. If I choose id :: Bool -> Bool then the question is: will the box spit out the value it contains? The answer is that the box will either spit out the value it contains or it will spit out nonsense (a bottom value like undefined). In other words, if you get an answer then that answer must be correct.
-- Get the a out of the box.
unbox :: Box a -> a
unbox f = f id
Because we can't generate arbitrary values in Haskell, the only sensical thing the box can do is apply the given function to the value it is hiding. This is a consequence of parametric polymorphism, also known as parametricity.
Now, to show that Box a is isomorphic to a, we need to prove two things about boxing and unboxing. We need to prove that you get out what you put in and that you can put in what you get out.
unbox . box = id
box . unbox = id
I'll do the first one and leave the second as an exercise for the reader.
unbox . box
= {- definition of (.) -}
\b -> unbox (box b)
= {- definition of unbox and (f a) b = f a b -}
\b -> box b id
= {- definition of box -}
\b -> id b
= {- definition of id -}
\b -> b
= {- definition of id, backwards -}
id
(If these proofs seem rather trivial, that's because all (total) polymorphic functions in Haskell are natural transformations and what we're proving here is naturality. Parametricity once again provides us with theorems for low, low prices!)
As an aside and another exercise for the reader, why can't I actually define rebox with (.)?
rebox = box . unbox
Why do I have to inline the definition of (.) myself like some sort of cave person?
rebox :: Box a -> Box a
rebox f = box (unbox f)
(Hint: what are the types of box, unbox, and (.)?)
Identity and Codensity and Yoneda, Oh My!
Now, how can we generalize Box? luqui uses Codensity: both bs are generalized by an arbitrary type constructor which we will call f. This is the Codensity transform of f a.
type CodenseBox f a = forall b. (a -> f b) -> f b
If we fix f ~ Identity then we get back Box. However, there's another option: we can hit only the return type with f:
type YonedaBox f a = forall b. (a -> b) -> f b
(I've sort of given away the game here with this name but we'll come back to that.) We can also fix f ~ Identity here to recover Box, but we let the box user pass in a normal function rather than a Kleisli arrow. To understand what we're generalizing, let's look again at the definition of box:
box a f = f a
Well, this is just flip ($), isn't it? And it turns out that our other two boxes are built by generalizing ($): CodenseBox is a partially applied, flipped monadic bind and YonedaBox is a partially applied flip fmap. (This also explains why Codensity f is a Monad and Yoneda f is a Functor for any choice of f: The only way to create one is by closing over a bind or fmap, respectively.) Furthermore, both of these esoteric category theory concepts are really generalizations of a concept that is familiar to many working programmers: the CPS transform!
In other words, YonedaBox is the Yoneda Embedding and the properly abstracted box/unbox laws for YonedaBox are the proof of the Yoneda Lemma!
TL;DR:
forall b. (a -> b) -> b === a is an instance of the Yoneda Lemma.
This question is a window into a number of deeper concepts.
First, note there is an ambiguity in this question. Do we mean the type forall b. (a -> b) -> b, such that we can instantiate b with whatever type we like, or do we mean (a -> b) -> b for some specific b that we cannot choose.
We can formalize this distinction in Haskell thus:
newtype Cont b a = Cont ((a -> b) -> b)
newtype Cod a = Cod (forall b. (a -> b) -> b)
Here we see some vocabulary. The first type is the Cont monad, the second is CodensityIdentity, though my familiarity with the latter term isn't strong enough to say what you should call that in English.
Cont b a can't be equivalent to a unless a -> b can hold at least as much information as a (see Dan Robertson's comment below). So, for example, notice that you can never get anything out of ContVoida.
Cod a is equivalent to a. To see this it is enough to witness the isomorphism:
toCod :: a -> Cod a
fromCod :: Cod a -> a
whose implementations I'll leave as an exercise. If you want to really do it up, you can try to prove that this pair really is an isomorphism. fromCod . toCod = id is easy, but toCod . fromCod = id requires the free theorem for Cod.
The other answers have done a great job describing the relationship between the types forall b . (a -> b) -> b and a but I'd like to point out one caveat because it leads to some interesting open questions that I have been working on.
Technically, forall b . (a -> b) -> b and a are not isomorphic in a langauge like Haskell which (1) allows you to write an expression that doesn't terminate and (2) is either call-by-value (strict) or contains seq. My point here is not to be nitpicky or show that parametricity is weakened in Haskell (as is well-known) but that there may be neat ways to strengthen it and in some sense reclaim isomorphisms like this one.
There are some terms of type forall b . (a -> b) -> b that cannot be expressed as an a. To see why, let's start by looking at the proof Rein left as an exercise, box . unbox = id. It turns out this proof is actually more interesting than the one in his answer, as it relies on parametricity in a crucial way.
box . unbox
= {- definition of (.) -}
\m -> box (unbox m)
= {- definition of box -}
\m f -> f (unbox m)
= {- definition of unbox -}
\m f -> f (m id)
= {- free theorem: f (m id) = m f -}
\m f -> m f
= {- eta: (\f -> m f) = m -}
\m -> m
= {- definition of id, backwards -}
id
The interesting step, where parametricity comes into play, is applying the free theorem f (m id) = m f. This property is a consequence of forall b . (a -> b) -> b, the type of m. If we think of m as a box with an underlying value of type a inside, then the only thing m can do with its argument is apply it to this underlying value and return the result. On the left side, this means that f (m id) extracts the underlying value from the box, and passes it to f. On the right, this means that m applies f directly to the underlying value.
Unfortunately, this reasoning doesn't quite hold when we have terms like the m and f below.
m :: (Bool -> b) -> b
m k = seq (k true) (k false)
f :: Bool -> Int
f x = if x then ⊥ else 2`
Recall we wanted to show f (m id) = m f
f (m id)
= {- definition f -}
if (m id) then ⊥ else 2
= {- definition of m -}
if (seq (id true) (id false)) then ⊥ else 2
= {- definition of id -}
if (seq true (id false)) then ⊥ else 2
= {- definition of seq -}
if (id false) then ⊥ else 2
= {- definition of id -}
if false then ⊥ else 2
= {- definition of if -}
2
m f
= {- definition of m -}
seq (f true) (f false)
= {- definition of f -}
seq (if true then ⊥ else 2) (f false)
= {- definition of if -}
seq ⊥ (f false)
= {- definition of seq -}
⊥
Clearly 2 is not equal to ⊥ so we have lost our free theorem and the isomorphism between a and (a -> b) -> b with it. But what happened, exactly? Essentially, m isn't just a nicely behaved box because it applies its argument to two different underlying values (and uses seq to ensure both of these applications are actually evaluated), which we can observe by passing in a continuation that terminates on one of these underlying values, but not the other. In other words, m id = false isn't really a faithful representation of m as a Bool because it 'forgets' the fact that m calls its input with both true and false.
The problem is a result of the interaction between three things:
The presence of nontermination.
The presence of seq.
The fact that terms of type forall b . (a -> b) -> b may apply their input multiple times.
There isn't much hope of getting around points 1 or 2. Linear types may give us an opportunity to combat the third issue, though. A linear function of type a ⊸ b is a function from type a to type b which must use its input exactly once. If we require m to have the type forall b . (a -> b) ⊸ b, then this rules out our counterexample to the free theorem and should let us show an isomorphism between a and forall b . (a -> b) ⊸ b even in the presence of nontermination and seq.
This is really cool! It shows that linearity has the ability to 'rescue' interesting properties by taming effects that can make true equational reasoning difficult.
One big issue remains, though. We don't yet have techniques to prove the free theorem we need for the type forall b . (a -> b) ⊸ b. It turns out current logical relations (the tools we normally use to do such proofs) haven't been designed to take into account linearity in the way that is needed. This problem has implications for establishing correctness for compilers that do CPS translations.

Pattern matching on types

Is there nice way to write the following "x is of type t" parts? (I suspect I should be using Data.Type.Equality but I'm not sure exactly how)
f :: a -> Int
g :: b -> Int
h :: Typeable t => t -> Maybe Int
h x = case x of
(x is of type a) -> Just (f x)
(x is of type b) -> Just (g x)
_ -> Nothing
Follow up question
This is a job for the "type safe cast" bits of Data.Typeable. cast :: (Typeable a, Typeable b) => a -> Maybe b pulls the runtime type information out of the Typeable dictionaries for a and b and compares them; if a and b are the same type then it returns Just its argument, otherwise it fails.
So, with cast and Maybe's Alternative instance in hand, we have:
h x = f <$> cast x
<|> g <$> cast x
As far as I know, there's no way to avoid the repetitious calls to cast, since they occur at different types.

Tricky type signature for pairs of reversed pairs

Lets say I have the following data type:
data D a b = D (a,b) (b,a)
And I want to define the following function on it:
apply f (D x y) = D (f x) (f y)
What is the type signature of apply?
Here are some examples of f which are okay:
f :: a -> a -- OK
f :: (a, b) -> (b, a) -- OK
f :: (a, b) -> ((a, c), (b, c)) -- OK
In all of the above cases, we end up with a valid type D.
But this is not okay:
f :: (a, b) -> (a, a)
Because when we send such a function through apply we end up having to attempt to construct D (a,a) (b,b) which is not valid unless a = b.
I can't seem to work out a type signature to express all this? Also, in general, is there a way to get GHC to tell me what these signatures should be?
Typed Holes Edit:
In an attempt to find the type using typed holes, I tried the following:
x = apply _ (D (1::Int,'a') ('b',2::Int))
And got:
Found hole ‘_’ with type: (Int, Int) -> (b, b)
Where: ‘b’ is a rigid type variable bound by
the inferred type of x :: D b b
Which seems to me to be nonsense as f :: (Int, Int) -> (b, b) is clearly not going to work here.
Multiple types fit apply, but the inferred ((t, t) -> (b, b)) -> D t t -> D b b is the most sensible and usable one. The alternatives are going to be higher-rank, so let's enable that language extension:
{-# LANGUAGE RankNTypes #-}
First, we can make apply id work:
apply :: (forall a. a -> a) -> D a b -> D a b
apply f (D x y) = D (f x) (f y)
However, now id is the only function with which apply works (all total functions of type forall a. a -> a are equal to id).
Here's another type:
apply :: (forall a. a -> (c, c)) -> D a b -> D c c
apply f (D x y) = D (f x) (f y)
But this too comes at a price. Now the f-s can only be constant functions that ignore the previous fields of D. So apply (const (0, 0)) works, but we have no way to inspect the argument of f.
In contrast, the inferred type is pretty useful. We can express transformations with it that look at the actual data contained in D.
At this point, we might ask: why does GHC infer what it infers? After all, some functions work with the alternative types, but don't work with the default type. Could it be better to sometimes infer higher-ranked types? Well, such types are often extremely useful, but inferring them is unfeasible.
Type inference for rank-2 types is rather complicated, and not very practical either, because it's not possible to infer most general types. With rank-1 inference, we can infer a type that is more general than all other valid types for the same expression. There's no such guarantee with rank-2 types. And inference for rank-3 and above types is just undecidable.
For these reasons, GHC sticks to rank-1 inference, so it never infers types with forall-s inside function arguments.
Taking things to extremes of generality, we want a type that looks like
apply :: tf -> D a b -> D c d
where tf represents the type of f. In order to apply f to (a,b) and get (c,d), we need
tf ~ (a,b) -> (c,d)
In order to apply f to (b,a) to get (d,c), we need
tf ~ (b,a) -> (d,c)
If we turn on TypeFamilies (or GADTs) we get the magic constraint we need to express that:
{-# LANGUAGE TypeFamilies #-}
apply :: (((a,b) -> (c,d)) ~ tf,
((b,a) -> (d,c)) ~ tf) =>
tf -> D a b -> D c d
I suspect this is one of the most general types available. Unfortunately, it's pretty wild; working through whether a particular application will pass the type checker is not always so easy. Note also that for reasons I don't personally understand, you can't reliably define specializations using
apply' :: ...
apply' = apply
Instead, you sometimes must use
apply' f = apply f

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.

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