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

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.

Related

Is Haskell's `Const` Functor analogous to the constant functor from category theory?

I understand that many of the names in Haskell are inspired by category theory terminology, and I'm trying to understand exactly where the analogy begins and ends.
The Category Hask
I already know that Hask is not (necessarily) a category due to some technical details about strictness/laziness and seq, but let's put that aside for now. For clarity,
The objects of Hask are concrete types, that is, types of kind *. This includes function types like Int -> [Char], but not anything that requires a type parameter like Maybe :: * -> *. However, the concrete type Maybe Int :: * belongs to Hask. Type constructors / polymorphic functions are more like natural transformations (or other more general maps from Hask to itself), rather than morphisms.
The morphisms of Hask are Haskell functions. For two concrete types A and B, the hom-set Hom(A,B) is the set of functions with signature A -> B.
Function composition is given by f . g. If we are worried about strictness, we might redefine composition to be strict or be careful about defining equivalence classes of functions.
Functors are Endofunctors in Hask
I don't think the technicalities above have anything to do with my confusion below. I think I understand it means to say that every instance of Functor is an endofunctor in the category Hask. Namely, if we have
class Functor (F :: * -> *) where
fmap :: (a -> b) -> F a -> F b
-- Maybe sends type T to (Maybe T)
data Maybe a = Nothing | Just a
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
the Functor instance Maybe corresponds to a functor from Hask to Hask in the following way:
To each concrete type a in Hask, we assign the concrete type Maybe a
To each morphism f :: A -> B in Hask, we assign the morphism Maybe A -> Maybe B which sends Nothing ↦ Nothing and Just x ↦ Just (f x).
The Constant (endo)Functor
The constant (endo)functor on a category C is a functor Δc : C → C mapping each object of the category C to a fixed object c∈C and each morphism of C to the identity morphism id_c : c → c for the fixed object.
The Const Functor
Consider Data.Functor.Const. For clarity, I will redefine it here, distinguishing between the type constructor Konst :: * -> * -> * and the data constructor Const :: forall a,b. a -> Konst a b.
newtype Konst a b = Const { getConst :: a }
instance Functor (Konst m) where
fmap :: (a -> b) -> Konst m a -> Konst m b
fmap _ (Const v) = Const v
This type checks because the data constructor Const is polymorphic:
v :: a
(Const v) :: forall b. Konst a b
I can buy that Konst m is an endofunctor in the category Hask, since in the implmenetation of fmap,
on the left-hand side, Const v manifests itself as a Konst m a, which is ok due to polymorphism
on the right-hand side, Const v manifests itself as a Konst m b, which is ok due to polymorphism
But my understanding breaks down if we try to think of Konst m :: * -> * as a constant functor in the category-theoretic sense.
What is the fixed object? The type constructor Konst m takes some concrete type a and gives us a Konst m a, which, at least superficially, is a different concrete type for every a. We really want to map each type a to the fixed type m.
According to the type signature, fmap takes an f :: a -> b and gives us a Konst m a -> Konst m b. If Konst m were analogous to the constant functor, fmap would need to send every morphism to the identity morphism id :: m -> m on the fixed type m.
Questions
So, here are my questions:
In what way is Haskell's Const functor analogous to the constant functor from category theory, if at all?
If the two notions are not equivalent, is it even possible to express the category-theoretic constant functor (call it SimpleConst, say) in Haskell code? I gave it a quick try and ran into the same problem with polymorphism wrt phantom types as above:
data SimpleKonst a = SimpleConst Int
instance Functor SimpleConst where
fmap :: (a -> b) -> SimpleConst a -> SimpleConst b
fmap _ (SimpleConst x) = (SimpleConst x)
If the answer to #2 is yes, If so, in what way are the two Haskell functions related in the category-theoretic sense? That is, SimpleConst is to Const in Haskell as the constant functor is to __?__ in category theory?
Do phantom types pose a problem for thinking of Hask like a category? Do we need to modify the definition of Hask so that objects are really equivalence classes of types that would otherwise be identical if not for the presence of a phantom type parameter?
Edit: A Natural Isomorphism?
It looks like the polymorphic function getConst :: forall a,b. Konst a b -> a is a candidate for a natural isomorphism η : (Konst m) ⇒ Δm from the functor Konst m to the constant functor Δm : Hask → Hask, even though I haven't been able to establish yet whether the latter is expressible in Haskell code.
The natural transformation law would be η_x = (Konst m f) . η_y. I'm having trouble proving it, since I'm not sure how to formally reason about the conversion of a (Const v) from type Konst m a to Konst m b, other than handwaving that "a bijection exists!".
Related References
Here is a list of possibly related questions / references not already linked above:
StackOverflow, "Do all Type Classes in Haskell have a Category-Theoretic Analogue?"
StackOverflow, "How are functors in Haskell related to functors in category theory?"
WikiBooks, Haskell/Category Theory
The problem we have here is that a functor is mathematically speaking a dependent pair, but it's a pair where one side (the Type -> Type mapping) lives in Haskell's type-level world, whereas the other side (the (a -> b) -> f a -> f b mapping) lives in the value-level world. Haskell doesn't have a way to express such pairs. The Functor class tricks its way around this limitation by allowing only type constructors as the Type -> Type mapping.
The reason this helps is that type constructors are unique, i.e. every one of them can be assigned a well-defined morphism-mapping through Haskell's typeclass mechanism. But the flip side is that, well, the result is always unique, so you end up with the situation where Konst Int Char and Konst Int Bool are technically speaking different, albeit isomorphic, types.
A more mathematical way of expressing functors would require a separate means of identifying at the type level what functor you mean. Then you only need a type-level mapping (which can be done with type families) and a type→value-level mapping (typeclass):
type family FunctorTyM f a :: Type
class FunctorMphM f where
fmap' :: (a -> b) -> FunctorTyM f a -> FunctorTyM f b
data KonstFtor a
type instance FunctorTyM (KonstFtor a) b = a
instance FunctorMphM (KonstFtor a) where
fmap' _ = id
This would still allow you to have also instances for the standard functors:
data IdentityFtor
type instance FunctorTyM IdentityFtor a = a
instance FunctorMphM IdentityFtor where
fmap' f = f
data ListFtor
type instance FunctorTyM ListFtor a = [a]
instance FunctorMphM ListFtor where
fmap' f = map f
But it would be more awkward to use in practice. You'll notice that the FunctorMphM class requires -XAllowAmbiguousTypes to compile – that's because f can't be inferred from FunctorTyM f. (We could ameliorate this with injective type families, but that would just get us back to the same issue we started with: the issue is precisely that the const functor is not injective!)
With modern Haskell, that's ok though, it just means you need to be explicit about what functor you're working with. (Arguably, that would often be a good thing anyway!) Full example:
{-# LANGUAGE TypeFamilies, AllowAmbiguousTypes, TypeApplications #-}
type family FunctorTyM f a
class FunctorMphM f where ...
data KonstFtor a
...
data IdentityFtor
...
data ListFtor
...
main :: IO ()
main = do
print (fmap' #(KonstFtor Int) (+2) 5)
print (fmap' #IdentityFtor (+2) 5)
print (fmap' #ListFtor (+2) [7,8,9])
Output:
5
7
[9,10,11]
This approach has some other advantages too. For instance we can finally express that tuples are functors in each of their arguments, not just in the rightmost one:
data TupleFstConst a
type instance FunctorTyM (TupleFstConst a) b = (a,b)
instance FunctorMphM (TupleFstConst a) where
fmap' f (x,y) = (x, f y)
data TupleSndConst b
type instance FunctorTyM (TupleSndConst b) a = (a,b)
instance FunctorMphM (TupleSndConst b) where
fmap' f (x,y) = (f x, y)
data TupleFtor
type instance FunctorTyM TupleFtor a = (a,a)
instance FunctorMphM TupleFtor where
fmap' f (x,y) = (f x, f y)
main :: IO ()
main = do
print (fmap' #(TupleFstConst Int) (+2) (5,50))
print (fmap' #(TupleSndConst Int) (+2) (5,50))
print (fmap' #TupleFtor (+2) (5,50))
(5,52)
(7,50)
(7,52)
Q. In what way is Haskell's Const functor analogous to the constant functor from category theory, if at all?
A. Const a b sends ant type b to a type isomorphic to a, instead of sending it to a as category-theoretic definition would require. This is not a big deal since isomorphic objects are "really the same object".
Q. If the two notions are not equivalent, is it even possible to express the category-theoretic constant functor (call it SimpleConst, say) in Haskell code?
A. They are not exactly equivalent, but they are equivalent up to an isomorphism, which is good enough. If you want exact equivalence, then it depends on what exactly you mean by "expressing a functor in code". Let's consider the identity functor as it's a bit simpler than Const. You can just write a type alias: type Id a = a and the associated morphism is just id. If you want to write an instance of Functor for this Id, then no, you can't do that in Haskell, because you cannot write class instances for type aliases (perhaps in some other similare language you could do that).
Q. [I]n what way are the two Haskell functions related in the category-theoretic sense?
A. There is no the const functor in category theory. There is a const functor for each object. Haskell Const a is related to such a const functor associated with object a. Haskell Const (no argument) is really a bifunctor (the right projection bifunctor if I'm not mistaken).
Q. Do phantom types pose a problem for thinking of Hask like a category? Do we need to modify the definition of Hask so that objects are really equivalence classes of types that would otherwise be identical if not for the presence of a phantom type parameter?
A. No, it is not a problem. Naturally isomorphic functors (or Functors) are "essentially the same". We say that in category theory "the ConstX functor sends any object to X", but we could just as well choose any functor naturally isomorphic to ConstX and study it instead. It would not change our mathematics in any meaningful way. We choose ConstX simply because it's the easiest one to define. In Haskell, Const X is the easiest one to define, so we use that as our the constant functor.
Addendum.
constIso1 :: Konst x a -> x
constIso1 (Const x) = x
constIso2 :: x -> Konst x a
constIso2 = Const
You're right that Konst m isn't quite a constant functor from a category-theory standpoint. But it's very closely related to one!
type CF m a = m
Now (CF m, id #m) really is a constant functor. I think the main lesson is that while we think of Functor as the class of endofunctors on Hask, it isn't really quite all of them.
I don't believe phantom types per se are an issue. Konst m a and Konst m b are different, but isomorphic, objects.

how do you determine if a type is a functor or not in haskell?

I have a data type:
data Tree a = Leaf | Branch a (Tree a) (Tree a)
I want to determine, and not just for this data type, but for others such as String, if these data types are law-abiding instances of functor (https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Functor.html). The link indicates that you can prove a type is a functor if it has a function fmap, which, given any types a and b, lets you apply any function of type (a -> b) to turn an f a into an f b, preserving the structure of f. How would I test this for my Tree data type, or String data type?
Short non-answer
Before you do any thinking yourself, try to let GHC write the instance for you:
{-# LANGUAGE DeriveFunctor #-}
data Tree a = Leaf | Branch a (Tree a) (Tree a)
deriving (Functor)
This happens to work in this case, and then you're guaranteed to have a law-abiding instance!
Seriously, this is the way you should typically acquire Functor instances for your data types. But you should still know yourself when it makes sense!
Actual Answer
I want to determine, and not just for this data type, but for others such as String, if these data types are law-abiding instances of Functor
So, for a Functor instance, you first of all need a parametric type, i.e. a “container” that doesn't care what type you store in it. So, strictly speaking the functor shouldn't be a type at all but a type constructor or type-level function★. Practically speaking, you see that by checking if the data declaration has type variables: in case of Tree you immediately see it in your code
data Tree a = ... ✓
If you don't have the source code handy, you can ask GHCi for the kind:
Prelude> :set -XTypeInType -XNoStarIsType†
Prelude> :k Maybe
Maybe :: Type -> Type ✓
Prelude> :k String
String :: Type ✗
As you see, String does not even have a type parameter, so it can't possibly be a functor.‡
Next, you need to look how the type variable is used in the data structure. If there are multiple type parameters, all of the following applies to the last (rightmost) of them, e.g. in data Either a b = ... we'd be talking about the b parameter.
If it's not used at all (i.e. if it's a phantom type argument) then you can trivially write a law-abiding Functor instance: just don't use the mapping-function either.
data Tough a = Tough String
instance Functor Tough where
fmap _ (Tough s) = Tough s
(However perhaps you shouldn't write a functor instance in this case, because phantom arguments are often meant to be constant unique tags.)
If it's used directly as part of one of fields in a type constructor, then you can write a functor instance. The fmap-ped function should then be applied to all those values.
data Maybe a = Nothing
| Just a
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just $ f a
If it's used somewhere deeper nested in the data structure, but all the nesting is in functors itself, then it's a functor. (This also holds up if it's the same functor you're just trying to define yourself, i.e. for recursive types!)
data TwoLists a = TwoLists {listL :: [a], listR :: [a]}
instance Functor TwoLists where
fmap f (TwoLists ll lr) = TwoLists (fmap f ll) (fmap f lr)
[Advanced, probably best if you ignore this for now] if the nesting consists of not normal (covariant) functors, but of an even number of contravariant functors, then your whole type is also a covariant functor.
★Type constructors are actually a very specific sort of type-level function, in particular they're injective. Mathematically speaking, a functor doesn't need to map its objects injectively (in case of Hask, the objects are types), but in Haskell this is necessary for the type checker.
†These syntactic extensions cause GHCi to show the kind of types as Type; historically it would show * instead and that's still the default in older GHC version, but now deprecated.
‡However, String is actually a synonym for [Char] i.e. a list of characters, and list is a functor. So you can actually perform fmap over a string, but that doesn't mean your using the “string functor”: you're using the list functor, and even if you started with a string the result may not be a string (but e.g. a list of integers).
Try to write such a function. If you succeed, it is definitely a Functor. If you fail, it might not be, or maybe you are not creative enough1. For Tree, it is relatively straightforward to implement, though of course a beginner may need to ask for help.
Specializing the signature of fmap to your Tree, you want a function with this signature:
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f Leaf = _
mapTree f (Branch value left right) = _
1 Actually there are many types that you can prove are not Functors just by looking at the fields of their constructors, but since that doesn't apply to Tree we won't get into it.
Warning: this is incomplete; I'm hoping someone can fill the hole I left regarding the functoriality of fixed points. Fact 5 and my use of it feel shaky.
String is not a functor, because it has the wrong kind. String :: Type, but a functor has to have kind Type -> Type.
Before we talk about Tree, let's establish a few facts.
Constant a (for any type a) is a functor:
-- From Data.Functor.Constant
newtype Constant a b = Constant { getConstant :: a }
instance Functor (Constant a) where
fmap _ (Constant x) = Constant x
Identity is a functor
-- Adapted from Data.Functor.Identity
newtype Identity a = Identity { runIdentity :: a }
instance Functor Identity where
fmap f (Identity x) = Identity (f x)
Sum types are functors, if the components are functors.
-- From Data.Functor.Sum
data Sum f g a = InL (f a) | InR (g a)
instance (Functor f, Functor g) => Functor (Sum f g) where
fmap f (InL x) = InL (fmap f x)
fmap f (InR y) = InR (fmap f y)
Product types are functors, if the components are functors
-- From Data.Functor.Product
data Product f g a = Pair (f a) (g a)
instance (Functor f, Functor g) => Functor (Product f g) where
fmap f (Pair x y) = Pair (fmap f x) (fmap f y)
Certain fixed points are functors.
-- From Data.Functor.Fixedpoint
newtype Fix f = Fix { unFix :: f (Fix f) }
instance (Functor f, Functor t) => Functor (Fix (f t)) where
fmap g (Fix h) = Fix (fmap g (unfix h))
With these facts in mind, we will decompose our Tree type into a combination of sums and products of known functors, which will thus establish that our type is isomorphic to a functor, and therefore a functor itself.
First, Leaf is just a descriptive alias for (), and we can replace the recursive reference to Tree a with another type parameter.
-- This is slightly different from some explanations of
-- recursive types, where t would be the subtree type itself, not
-- a type constructor.
data TreeF t a = () | Branch a (t a) (t a)
Next, we get rid of a by noticing that the type () is isomorphic to Constant () a and a is isomorphic to Identity a. Further, a three-way product is isomorphic to two two-way products (i.e., (a, b, c) ~ (a, (b, c))):
-- Algebraically, T a = 1 + a*T*T
data TreeF t = Sum (Constant ()) (Product Identity (Product t t))
Facts 1-4 above allow us to conclude that TreeF t is a functor whenever t is a functor.
Finally, we can use "fact" 5 to conclude that Fix TreeF (Fix TreeF) ~ Tree is a functor.

Defining your own Functor

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.

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.

instance of "Type constructed with type argument" need not be constructed with data of that type, in Haskell

In Haskell, a type constructor can take a type argument, of course.
A function a -> b, when looked at as a "type with a funny constructor name", has type (->) a b. That makes it a type constructor (->) with two arguments, a and b. This is frequently encountered in the "reader" pattern as in its Functor and Applicative instances:
instance Functor ((->) a) where
fmap = (.)
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
When I first tried to understand uses of this instance, as in
fmap (+1) (*2) 3 (=== (+1) . (*2) $ 3 === 3*2+1 === 7)
my reaction was "Ok, (+1) has type Int -> Int, which is (->) Int Int, so that matches Functor.... but where is the Int? I make a Maybe Int by calling Just 1, but I don't ever make a (->) Int Int by applying anything to an Int. In fact, I destroy a ((->) Int Int) by applying it to an Int! (Yeah, there's Nothing, but that seems... degenerate.)"
This all works (of course), as long as I remember that just because a type is built from a constructor+argument, that doesn't mean its values are built from a correspondingly typed constructor+argument. And some of the most interesting and powerful (and tricky to understand) type constructors are like this ((->), Lens, Arrow, etc)
(OK, really it's Num a => a, not Int, but let's ignore that, not relevant)
Is there a name for this concept? What is the appropriate mental model for thinking about type constructors, without leaning on the misleading and disempowering crutch interpretation "Foo a is a structure Foo containing value(s) of type a)?
This concept is known as a contravariant functor, on in Haskell-speak a Contravariant type.
class Contravariant f where
contramap :: (b -> a) -> f a -> f b
-- compare
class Functor f where
fmap :: (a -> b) -> f a -> f b
More generally, we can think of type variables in a type as having contravariant or covariant nature (at its simplest). For instance, by default we have
newtype Reader t a = Reader (t -> a)
instance Functor (Reader t) where
fmap ab (Reader ta) = Reader (ab . ta)
Which indicates that the second type parameter to Reader is covariant, while if we reverse the order
newtype RevReader a t = RevReader (t -> a)
instance Contravariant (RevReader a) where
contramap st (RevReader ta) = RevReader (ta . st)
A useful intuition for Contravariant types is that they have the ability to consume zero, one, or many values of the contravariant parameter instead of containing zero, one, or many values of the covariant parameter like we often think of when considering Functors.
Combining these two notions is the Profunctor
class Profunctor p where
dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
which, as we notice, demands that p is of kind * -> * -> * where the first type parameter is contravariant and the second covariant. This class well characterizes the (->) type constructor
instance Profuntor (->) where
dimap f g h = g . h . f
Again, if we think of contravariant type parameters as being consumed and covariant ones as being produced this is quite amenable of the typical intuition around (->) types.
A few more examples of types which contravariant parameters include Relation
newtype Relation t = Relation (t -> t -> Bool)
instance Contravariant Relation where
contramap g (Relation pred) = Relation $ \a b -> pred (g a) (g b)
Or Fold which represents a left fold as a data type
newtype Fold a b = Fold b (a -> Fold a b)
instance Profunctor Fold where
dimap f g (Fold b go) = Fold (g b) (go . f)
sumF :: Num a => Fold a a
sumF = go 0 where
go n = Fold n (\i -> go (n + i))
With Fold a b we see that it consumes an arbitrary number of a types to produce one b type.
Generally what we find is that while it's often the case that we have covariant and "container" (strictly positive) types where values of some type c a are produced from a constructor of type a -> c a and some filler values a, in general that doesn't hold. In particular we have covariant types like that, but also contravariant ones which are often processes which somehow consume values of their parameterized type variables, or even more exotic ones like phantom types which utterly ignore their type variables
newtype Proxy a = Proxy -- need no `a`, produce no `a`
-- we have both this instance
instance Functor Proxy where
fmap _ Proxy = Proxy
-- and this one, though both instances ignore the passed function
instance Contravariant Proxy where
contramap _ Proxy = Proxy
and... "nothing special" type variables which cannot have any sort of nature, usually because they're being used as both covariant and contravariant types.
data Endo a = Endo (a -> a)
-- no instance Functor Endo or Contravariant Endo, it needs to treat
-- the input `a` differently from the output `a` such as in
--
-- instance Profunctor (->) where
Finally, a type constructor which takes multiple arguments may have different natures for each argument. In Haskell, the final type parameter is usually treated specially, though.

Resources