From page 3 of http://research.microsoft.com/en-us/um/people/emeijer/Papers/meijer94more.pdf:
it is not true in general that catamorphisms are closed under composition
Under what conditions do catamorphisms compose to a catamorphism? More specifically (assuming I understood the statement correctly):
Suppose I have two base functors F and G and folds for each: foldF :: (F a -> a) -> (μF -> a) and foldG :: (G a -> a) -> (μG -> a).
Now suppose I have two algebras a :: F μG -> μG and b :: G X -> X.
When is the composition (foldG b) . (foldF a) :: μF -> X a catamorphism?
Edit: I have a guess, based on dblhelix's expanded answer: that outG . a :: F μG -> G μG must be the component at μG of some natural transformation η :: F a -> G a. I don't know whether this is right. (Edit 2: As colah points out, this is sufficient but not necessary.)
Edit 3: Wren Thornton on Haskell-Cafe adds: "If you have the right kind of distributivity property (as colah suggests) then things will work out for the particular case. But, having the right kind of distributivity property typically amounts to being a natural transformation in some appropriately related category; so that just defers the question to whether an appropriately related category always exists, and whether we can formalize what "appropriately related" means."
When is the composition (fold2 g) . (fold1 f) :: μF1 -> A a catamorphism?
When there exists an F1-algebra h :: F1 A -> A such that fold1 h = fold2 g . fold1 f.
To see that catamorphisms are in general not closed under composition, consider the following generic definitions of type-level fixed point, algebra, and catamorphism:
newtype Fix f = In {out :: f (Fix f)}
type Algebra f a = f a -> a
cata :: Functor f => Algebra f a -> Fix f -> a
cata phi = phi . fmap (cata phi) . out
For catamorphisms to compose we would need
algcomp :: Algebra f (Fix g) -> Algebra g a -> Algebra f a
Now try writing this function. It takes two functions as arguments (of types f (Fix g) -> Fix g and g a -> a respectively) and a value of type f a, and it needs to produce a value of type a. How would you do that? To produce a value of type a your only hope is to apply the function of type g a -> a, but then we are stuck: we have no means to turn a value of type f a into a value of type g a, have we?
I am not sure whether this is of any use for your purposes, but an example of a condition under which one can compose to catamorphisms is if we have a morphism from the result of the second cata to the fixed point of the second functor:
algcomp' :: (Functor f, Functor g) =>
(a -> Fix g) -> Algebra f (Fix g) -> Algebra g a -> Algebra f a
algcomp' h phi phi' = cata phi' . phi . fmap h
(Disclaimer: This is outside my area of expertise. I believe I'm correct (with caveats provided at different points), but ... Verify it yourself.)
A catamorphism can be thought of as a function that replaces constructors of a data type with other functions.
(In this example, I will be using the following data types:
data [a] = [] | a : [a]
data BinTree a = Leaf a | Branch (BinTree a) (BinTree a)
data Nat = Zero | Succ Nat
)
For example:
length :: [a] -> Nat
length = catamorphism
[] -> 0
(_:) -> (1+)
(Sadly, the catamorphism {..} syntax is not available in Haskell (I saw something similar in Pola). I've been meaning to write a quasiquoter for it.)
So, what is length [1,2,3]?
length [1,2,3]
length (1 : 2 : 3 : [])
length (1: 2: 3: [])
1+ (1+ (1+ (0 )))
3
That said, for reasons that will become apparent later, it is nicer to define it as the trivially equivalent:
length :: [a] -> Nat
length = catamorphism
[] -> Zero
(_:) -> Succ
Let's consider a few more example catamorphisms:
map :: (a -> b) -> [a] -> b
map f = catamorphism
[] -> []
(a:) -> (f a :)
binTreeDepth :: Tree a -> Nat
binTreeDepth = catamorphism
Leaf _ -> 0
Branch -> \a b -> 1 + max a b
binTreeRightDepth :: Tree a -> Nat
binTreeRightDepth = catamorphism
Leaf _ -> 0
Branch -> \a b -> 1 + b
binTreeLeaves :: Tree a -> Nat
binTreeLeaves = catamorphism
Leaf _ -> 1
Branch -> (+)
double :: Nat -> Nat
double = catamorphism
Succ -> Succ . Succ
Zero -> Zero
Many of these can be nicely composed to form new catamorphisms. For example:
double . length . map f = catamorphism
[] -> Zero
(a:) -> Succ . Succ
double . binTreeRightDepth = catamorphism
Leaf a -> Zero
Branch -> \a b -> Succ (Succ b)
double . binTreeDepth also works, but it is almost a miracle, in a certain sense.
double . binTreeDepth = catamorphism
Leaf a -> Zero
Branch -> \a b -> Succ (Succ (max a b))
This only works because double distributes over max... Which is pure coincidence. (The same is true with double . binTreeLeaves.) If we replaced max with something that didn't play as nicely with doubling... Well, let's define ourselves a new friend (that doesn't get along as well with the others). For a binary operators that double doesn't distribute over, we'll use (*).
binTreeProdSize :: Tree a -> Nat
binTreeProdSize = catamorphism
Leaf _ -> 0
Branch -> \a b -> 1 + a*b
Let's try to establish sufficient conditions for two catamorphisms two compose. Clearly, any catamorphism will quite happily be composed with length, double and map f because they yield their data structure without looking at the child results. For example, in the case of length, you can just replace Succ and Zero with what ever you want and you have your new catamorphism.
If the first catamorphism yields a data structure without looking at what happens to its children, two catamorphisms will compose into a catamorphism.
Beyond this, things become more complicated. Let's differentiate between normal constructor arguments and "recursive arguments" (which we will mark with a % sign). So Leaf a has no recursive arguments, but Branch %a %b does. Let's use the term "recursive-fixity" of a constructor to refer to the number of recursive arguments it has. (I've made up both these terms! I have no idea what proper terminology is, if there is one! Be wary of using them elsewhere!)
If the first catamorphism maps something into a zero recursive fixity constructor, everything is good!
a | b | cata(b.a)
===============================|=========================|================
F a %b %c .. -> Z | Z -> G a b .. | True
If we map children directly into a new constructor, we're also good.
a | b | cata(b.a)
===============================|=========================|=================
F a %b %c .. -> H %c %d .. | H %a %b -> G a b .. | True
If we map into a recursive fixity one constructor...
a | b | cata(b.a)
===============================|=========================|=================
F a %b %c .. -> A (f %b %c..) | A %a -> B (g %a) | Implied by g
| | distributes over f
But it isn't iff. For example, if there exist g1 g2 such that g (f a b..) = f (g1 a) (g2 b) .., that also works.
From here, the rules will just get messier, I expect.
Catamorphisms de-construct a data structure into a result value. So, in general, when you apply a catamorphism, the result is something completely different, and you cannot apply another catamorphism to it.
For example, a function that sums all elements of [Int] is a catamorphism, but the result is Int. There is no way how to apply another catamorphism on it.
However, some special catamorphisms create a result of the same type as the input. One such example is map f (for some given function f). While it de-constructs the original structure, it also creates a new list as its result. (Actually, map f can be viewed both as a catamorphism and as an anamorphism.) So if you have such a class of special catamorphisms, you can compose them.
If we consider semantic equivalence, the composition of two catamorphisms is a catamorphism, when the first one is a hylomorphism:
cata1 . hylo1 = cata2
For example (Haskell):
sum . map (^2) = foldl' (\x y -> x + y^2) 0
Related
I admit, that my question may stem from a lack of knowledge and be rather vague.
But I try to understand, have some doubts and can't resolve them.
So GHC.Base have such definition, and what is the sense in it:
instance Functor ((->) r) where
fmap = (.)
From the viewpoint of programming language:
We have really base construction (->), I think more base than anything, but maybe terms, and you describe it as a part of very derivative construction (instance Functor). What is the sense? (->) is (->). Functor have any sense as far as (->) described under Haskell hood meaningfully. But not vice versa: (->) have sense while Functor described in Haskell libraries correctly.
From the viewpoint of lambda calculus:
2.1 If from "common sense" definition "(->) r" is a container around r (let's call it "Any_f"), then how function fmap shoul work?
fmap should change value into container, but do not change container-structure, try to write it.
fmap f (Any_f x) <=> Any_f (f x)
(yes, this is non-typed lambda calculus)
2.2. But let's look how Functor ((->) r) defined in Haskell:
instance Functor ((->) r) where
fmap = (.)
-- Or in other words (quotation marks intentionaly):
-- fmap f (Any_f x) = f (Any_f x)
-- fmap :: forall a, b, c => (b -> c) -> (a -> b) -> (a -> c)
So:
"common sense" (not change container structure) tells us to write:
fmap f (Any_f_as_container x) = Any_f_as_container (f x)
types requirements tell us to write:
fmap f (any_f_as_container x) = f (Any_f_as_container x)
Doesn't this means that "instance Functor ((->) r)" is meaningless? And if not - what sense does it has when it changes outermost function (container itself, not container value)?
I will try to convince you that fmap = (.) really is a thing that leaves a container's shape the same, but applies a function to all the elements in the container. But before we do that for (->), let's do it for some simpler types. Specifically, let's do it for types that are containers with a specific number of elements -- i.e., a container with exactly two elements will be TwoF, while one with no elements will be ZeroF. Like this:
data ZeroF a = ZeroF
data OneF a = OneF a
data TwoF a = TwoF a a
data ThreeF a = ThreeF a a a
What should the Functor instances for these look like? Well, the one for OneF looks exactly like in your question:
instance Functor OneF where
fmap f (OneF x) = OneF (f x)
The other ones look pretty similar -- just applying f more (or fewer) times to account for the fact that there are more (or fewer) elements. Here they all are, with some creative whitespace to highlight the similarities/pattern:
instance Functor ZeroF where fmap f (ZeroF ) = ZeroF
instance Functor OneF where fmap f (OneF x0 ) = OneF (f x0)
instance Functor TwoF where fmap f (TwoF x0 x1 ) = TwoF (f x0) (f x1)
instance Functor ThreeF where fmap f (ThreeF x0 x1 x2) = ThreeF (f x0) (f x1) (f x2)
Hopefully for now you agree that this definitely has the flavor of Functor instance that you described in your question: keep the shape of the container the same, and apply the given function f to each element contained within.
So those are containers with a given number of elements. Now, let's write accessors for these containers -- i.e. we want the equivalent of (!!) for lists, where given a number, we pull out that field from the container. Since there's zero elements in a ZeroF, we'll need an indexing type with zero values; while for ThreeF we need an indexing type with three values.
data Zero
data One = One0
data Two = Two0 | Two1
data Three = Three0 | Three1 | Three2
The indexing functions have types that look like this:
indexZero :: ZeroF a -> Zero -> a
indexOne :: OneF a -> One -> a
indexTwo :: TwoF a -> Two -> a
indexThree :: ThreeF a -> Three -> a
I won't implement them all -- they're pretty straightforward -- but here's one to give you the idea in case it's not immediately obvious.
indexTwo (TwoF x0 x1) Two0 = x0
indexTwo (TwoF x0 x1) Two1 = x1
It turns out that the indexing functions have an inverse -- if you give me a function which, when given an index, produces a value, then I can give you a container with those values in it. The types look like this:
tabulateZero :: (Zero -> a) -> ZeroF a
tabulateOne :: (One -> a) -> OneF a
tabulateTwo :: (Two -> a) -> TwoF a
tabulateThree :: (Three -> a) -> ThreeF a
(Do you see why this is the right type for an inverse? Note that, say, TwoF a -> Two -> a is the same type as TwoF a -> (Two -> a)!) Just to give you an idea of how these are implemented, in case it's not immediately obvious, we simply apply the indexing function to each index:
tabulateZero ix = ZeroF
tabulateOne ix = OneF (ix One0 )
tabulateTwo ix = TwoF (ix Two0 ) (ix Two1 )
tabulateThree ix = ThreeF (ix Three0) (ix Three1) (ix Three2)
It's not too hard to prove that tabulateX . indexX = id and indexX . tabulateX = id for each X, i.e. that tabulation really is the inverse of indexing.
Okay, but hold up now and take a look at what we've just done: we have turned a function (like Two -> a) into a container (like TwoF a), and vice versa. The types Two -> a and TwoF a are, morally speaking, exactly the same thing. So it seems reasonable to think we could implement fmap for Two -> a -- for example, just by converting to TwoF a and back as appropriate!
twomap :: (a -> b) -> (Two -> a) -> (Two -> b)
twomap f = indexTwo . fmap f . tabulateTwo
Let's visualize what that's doing. We'll start with an arbitrary indexing function:
\case Two0 -> x0; Two1 -> x1
Now we go through the process:
\case Two0 -> x0; Two1 -> x1
tabulateTwo
TwoF x0 x1
fmap f
TwoF (f x0) (f x1)
indexTwo
\case Two0 -> f x0; Two1 -> f x1
Since f gets applied in both branches, we could pull that out of the case:
f . (\case Two0 -> x0; Two1 -> x1)
That second term is exactly the indexing function we started out with. In other words, we have just determined another, simpler implementation for twomap:
twomap f ix = f . ix
If you work through similar reasoning for zeromap, onemap, and threemap, you'll discover they actually all have that same implementation! We can do this uniformly for all the various sizes of container just by going polymorphic; instead of having onemap for changing One -> a's, etc., let's have an xmap for changing x -> a's:
xmap :: (a -> b) -> (x -> a) -> (x -> b)
xmap f ix = f . ix
Of course, we don't have to name f and ix:
xmap = (.)
...and this is the Functor instance for (x -> _).
(->) isn't just syntax. It's an operator like any other, but at the type level instead of the term level. It has a kind Type -> Type -> Type, which means if you apply it to a single type, you get back not a type, but another "function" of kind Type -> Type.
Type -> Type is the kind of all functors, so it's reasonable to think the partially applied (->) operator might be a functor as well, which is what
instance Functor ((->) r) where
fmap = (.)
defines. That is, mapping a function over another function means to compose the two functions.
As a "container", think of a function (something of type r -> a) as containing all possible values of type a that you can get by applying the function to an argument of type r. fmap will apply a function to whatever the other function returns. (Or in theory, apply it to every value that the other could return.)
So the answer is: functions can be represent either as (a -> b) or as Map a b - for function with finite count of possible arguments these are literally two equivalent representations.
So instance Functor (Map r) is meaningful and it would be implemented just as instance Functor ((->) r) implemented already.
And the answer above is confirmed by the implementation of instance Functor ((,) r). Yes this is a bit different than Map r, but as close as possible.
P.S.
#chepner : I can't mark your answer as "best answer" because I don't understand (and almost don't agree) with one word in one sentense:
(->) isn't just syntax. It's an operator like any other
Function is not "like any other" operation (I used notion "construction") function is magical- or under-hood-compiler- construction, on which all other fuctions are based.
While learning about the Yoneda lemma, I came across the following encoding of the underlying natural isomorphism in Haskell:
forward :: Functor f => (forall r . (a -> r) -> f r) -> f a
forward f = f id
backward :: Functor f => f a -> (forall r. (a -> r) -> f r)
backward x f = fmap f x
I tried to simplify the implementation of backward to flip fmap but failed as the latter has type f a -> (a -> r) -> f r.
From here on I'm stuck in pinpointing what precisely are the differences between the two implementations. More so as applying either function to a concrete functor yields the same result type:
ghci> :t bw (Just "")
bw (Just "") :: (String -> r) -> Maybe r
ghci> :t (flip fmap) (Just "")
(flip fmap) (Just "") :: (String -> r) -> Maybe r
Questions:
What exactly is the difference between the two?
Is there something I can do with one that can't be done with the other?
Why is the universal quantification needed at all for backward?
In Haskell we write lambdas for the values we pass:
id :: forall a . a->a
id = \x -> x
but when we compile to the lower-level Core language, which is closed to System F, we also see type lambdas. The code becomes more like
id = \ #a (x :: #a) -> x
which means: the caller should choose and pass a type #a, then a value of that type x :: #a and finally receive that value back x.
Now, your issue arises from the two (isomorphic) types
forall a . T -> U a
-- vs
T -> forall a . U a
Here, T does not depend on a. The two types are indeed isomorphic, and at the lower level it's just a matter of "flipping" the term-lambda with the type-lambda:
\ #a (x :: T) -> ... -- has the former type
-- vs
\ (x :: T) #a -> ... -- has the latter
Since in Haskell we do not usually write or see the type-lambdas, it is hard to distinguish between these. Further, when the compiler performs type inference it will (as far as I can understand) infer the first one, where the type-lambdas are all at the beginning.
What exactly is the difference between the two?
Not much. They have isomorphic types, after all. One has the forall a at the topmost level, while the other has it in another position.
Once you apply then to arguments as you did, GHC will automatically choose the right place to add the inferred #a argument, so you won't easily notice the difference. The two calls are of these forms:
f #r x
-- vs
f x #r
On top, GHC can re-generalize the type, hence we obtain
(\#r -> f #r x) :: forall r . ....
(\#r -> f x #r) :: forall r . ....
Is there something I can do with one that can't be done with the other?
Not really.
Why is the universal quantification needed at all for backward?
Usually, when defining an isomorphism between A and B we want
forw :: A -> B
back :: B -> A
If either type has a forall (say, A = forall r . V r) then we get a forall in that position. Note that the type for back in this case is also isormoprhic to
forall r . B -> V r
which is what we would get if we omitted the quantifier (and let Haskell re-add it implicitly at the top-level).
(By contrast, the quantifier in the type of forw :: (forall r . V r) -> B can not be moved to the top level.)
I'm reading the second edition of Programming in Haskell and I've came across this sentence:
... there is only one way to make any given parameterised type into a functor, and hence any function with the same polymorphic type as fmap must be equal to fmap.
This doesn't seem right to me, though. I can see that there is only one valid definition of fmap for each Functor type, but surely I could define any number of functions with the type (a -> b) -> f a -> f b which aren't equivalent to each other?
Why is this the case? Or, is it just a mistake by the author?
You've misread what the author was saying.
...any function with the same polymorphic type as fmap...
This means, any function with the signature
Functor f => (a -> b) -> f a -> f b
must be equivalant to fmap. (Unless you permit bottom values, of course.)
That statement is true; it can be seen quite easily if you try to define such a function: because you know nothing about f except that it's a functor, the only way to obtain a non-⊥ f b value is by fmapping over the f a one.
What's a bit less clear cut is the logical implication in the quote:
there is only one way to make any given parameterised type into a functor, and hence any function with the same polymorphic type as fmap must be equal to fmap.
I think what the author means there is, because a Functor f => (a -> b) -> f a -> f b function must necessarily invoke fmap, and because fmap is always the only valid functor-mapping for a parameterised type, any Functor f => (a -> b) -> f a -> f b will indeed also in practice obey the functor laws, i.e. it will be the fmap.
I agree that the “hence” is a bit badly phrased, but in principle the quote is correct.
I think that the quote refers to this scenario. Assume we define a parameterized type:
data F a = .... -- whatever
for which we can write not only one, but two fmap implementations
fmap1 :: (a -> b) -> F a -> F b
fmap2 :: (a -> b) -> F a -> F b
satisfying the functor laws
fmap1 id = id
fmap1 (f . g) = fmap1 f . fmap1 g
fmap2 id = id
fmap2 (f . g) = fmap2 f . fmap2 g
Under these assumptions, we have that fmap1 = fmap2.
This is a theoretical consequence of the "free theorem" associated to fmap's polymorphic type (see the comment under Lemma 1).
Pragmatically, this ensures that the instance we obtain from deriving Functor is the only possible one.
It is a mistake. Here's some examples of functions with the same type as fmap for lists that are not fmap:
\f -> const []
\f -> concatMap (replicate 2 . f)
\f -> map (f . head) . chunksOf 2
\f -> map f . reverse
There are many more. In general, given a function ixf from list lengths to lists of numbers no bigger than that length (that is, valid indices into the list), we can build
maybeIt'sFmapLol :: (Int -> [Int]) -> (a -> b) -> [a] -> [b]
maybeIt'sFmapLol ixf elemf xs = [map elemf xs !! ix | ix <- ixf (length xs)]
Use suitably lazy variants of Int to handle infinite lists. A similar function schema can be cooked up for other container-like functors.
Or to be specific, why do we use foldr to encode lists and iteration to encode numbers?
Sorry for the longwinded introduction, but I don't really know how to name the things I want to ask about so I'll need to give some exposition first. This draws heavily from this C.A.McCann post that just not quite satisfies my curiosity and I'll also be handwaving the issues with rank-n-types and infinite lazy things.
One way to encode datatypes as functions is to create a "pattern matching" function that receives one argument for each case, each argument being a function that receives the values corresponding to that constructor and all arguments returning a same result type.
This all works out as expected for non-recursive types
--encoding data Bool = true | False
type Bool r = r -> r -> r
true :: Bool r
true = \ct cf -> ct
false :: Bool r
false = \ct cf -> cf
--encoding data Either a b = Left a | Right b
type Either a b r = (a -> r) -> (b -> r) -> r
left :: a -> Either a b r
left x = \cl cr -> cl x
right :: b -> Either a b r
right y = \cl cr -> cr y
However, the nice analogy with pattern matching breaks down with recursive types. We might be tempted to do something like
--encoding data Nat = Z | S Nat
type RecNat r = r -> (RecNat -> r) -> r
zero = \cz cs -> cz
succ n = \cz cs -> cs n
-- encoding data List a = Nil | Cons a (List a)
type RecListType a r = r -> (a -> RecListType -> r) -> r
nil = \cnil ccons -> cnil
cons x xs = \cnil ccons -> ccons x xs
but we can't write those recursive type definitions in Haskell! The usual solution is to force the callback of the cons/succ case to be applied to all levels of recursion instead of just the first one (ie, writing a fold/iterator). In this version we use the return type r where the recursive type would be:
--encoding data Nat = Z | S Nat
type Nat r = r -> (r -> r) -> r
zero = \cz cf -> cz
succ n = \cz cf -> cf (n cz cf)
-- encoding data List a = Nil | Cons a (List a)
type recListType a r = r -> (a -> r -> r) -> r
nil = \z f -> z
cons x xs = \z f -> f x (xs z f)
While this version works, it makes defining some functions much harder. For example, writing a "tail" function for lists or a "predecessor" function for numbers is trivial if you can use pattern matching but gets tricky if you need to use the folds instead.
So onto my real questions:
How can we be sure that the encoding using folds is as powerful as the hypothetical "pattern matching encoding"? Is there a way to take an arbitrary function definition via pattern matching and mechanically convert it to one using only folds instead? (If so, this would also help make tricky definitions such as tail or foldl in terms of foldr as less magical)
Why doesn't the Haskell type system allow for the recursive types needed in the "pattern matching" encoding?. Is there a reason for only allowing recursive types in datatypes defined via data? Is pattern matching the only way to consume recursive algebraic datatypes directly? Does it have to do with the type inferencing algorithm?
Given some inductive data type
data Nat = Succ Nat | Zero
we can consider how we pattern match on this data
case n of
Succ n' -> f n'
Zero -> g
it should be obvious that every function of type Nat -> a can be defined by giving an appropriate f and g and that the only ways to make a Nat (baring bottom) is using one of the two constructors.
EDIT: Think about f for a moment. If we are defining a function foo :: Nat -> a by giving the appropriate f and g such that f recursively calls foo than we can redefine f as f' n' (foo n') such that f' is not recursive. If the type a = (a',Nat) than we can instead write f' (foo n). So, without loss of generality
foo n = h $ case n
Succ n' -> f (foo n)
Zero -> g
this is the formulation that makes the rest of my post make sense:
So, we can thus think about the case statement as applying a "destructor dictionary"
data NatDict a = NatDict {
onSucc :: a -> a,
onZero :: a
}
now our case statement from before can become
h $ case n of
Succ n' -> onSucc (NatDict f g) n'
Zero -> onZero (NatDict f g)
given this we can derive
newtype NatBB = NatBB {cataNat :: forall a. NatDict a -> a}
we can then define two functions
fromBB :: NatBB -> Nat
fromBB n = cataNat n (NatDict Succ Zero)
and
toBB :: Nat -> NatBB
toBB Zero = Nat $ \dict -> onZero dict
toBB (Succ n) = Nat $ \dict -> onSucc dict (cataNat (toBB n) dict)
we can prove these two functions are witness to an isomorphism (up to fast and lose reasoning) and thus show that
newtype NatAsFold = NatByFold (forall a. (a -> a) -> a -> a)
(which is just the same as NatBB) is isomorphic to Nat
We can use the same construction with other types, and prove that the resulting function types are what we want just by proving that the underlying types are isomorphic with algebraic reasoning (and induction).
As to your second question, Haskell's type system is based on iso-recursive not equi-recursive types. This is probably becuase the theory and type inference is easier to work out with iso-recursive types, and they have all the power they just impose a little more work on the programmers part. I like to claim that you can get your iso-recursive types without any overhead
newtype RecListType a r = RecListType (r -> (a -> RecListType -> r) -> r)
but apparently GHCs optimizer chokes on those sometimes :(.
The Wikipedia page on Scott encoding has some useful insights. The short version is, what you're referring to is the Church encoding, and your "hypothetical pattern-match encoding" is the Scott encoding. Both are sensible ways of doing things, but the Church encoding requires lighter type machinery to use (in particular, it does not require recursive types).
The proof that the two are equivalent uses the following idea:
churchfold :: (a -> b -> b) -> b -> [a] -> b
churchfold _ z [] = z
churchfold f z (x:xs) = f x (churchfold f z xs)
scottfold :: (a -> [a] -> b) -> b -> [a] -> b
scottfold _ z [] = z
scottfold f _ (x:xs) = f x xs
scottFromChurch :: (a -> [a] -> b) -> b -> [a] -> b
scottFromChurch f z xs = fst (churchfold g (z, []) xs)
where
g x ~(_, xs) = (f x xs, x : xs)
The idea is that since churchfold (:) [] is the identity on lists, we can use a Church fold that produces the list argument it is given as well as the result it is supposed to produce. Then in the chain x1 `f` (x2 `f` (... `f` xn) ... ) the outermost f receives a pair (y, x2 : ... : xn : []) (for some y we don't care about), so returns f x1 (x2 : ... : xn : []). Of course, it also has to return x1 : ... : xn : [] so that any more applications of f could also work.
(This is actually a little similar to the proof of the mathematical principle of strong (or complete) induction, from the "weak" or usual principle of induction).
By the way, your Bool r type is a bit too big for real Church booleans – e.g. (+) :: Bool Integer, but (+) isn't really a Church boolean. If you enable RankNTypes then you can use a more precise type: type Bool = forall r. r -> r -> r. Now it is forced to be polymorphic, so genuinely only contains two (ignoring seq and bottom) inhabitants – \t _ -> t and \_ f -> f. Similar ideas apply to your other Church types, too.
The type of fmap in Functor is:
fmap :: Functor f => (a -> b) -> f a -> f b
it looks like ,first apply function (a -> b) to the parameter of f a to create a result of type b, then apply f to it, and result is f b
using Maybe a for example:
fmap show (Just 1)
result is : Just "1"
same as saying:
Just (show 1)
but when (->) is used as a Functor (in Control.Monad.Instances)
import Control.Monad.Instances
(fmap show Just) 1
result is : "Just 1"
that is, Just is applied first, then show is applied. In another example ,result is same:
fmap (*3) (+100) 1
result is 303
why not *3 first, then +100?
The fmap instance for (->) r (i.e. functions) is literally just composition. From the source itself:
instance Functor ((->) r) where
fmap = (.)
So, in your example, we can just replace fmap with (.), and do some transformations
fmap (*3) (+100) 1 =>
(.) (*3) (+100) 1 =>
(*3) . (+100) $ 1 => -- put (.) infix
(*3) (1 + 100) => -- apply (+100)
(1 + 100) * 3 -- apply (*3)
That is, fmap for functions composes them right to left (exactly the same as (.), which is sensible because it is (.)).
To look at it another way (for (double) confirmation!), we can use the type signature:
-- general fmap
fmap :: Functor f => (a -> b) -> f a -> f b
-- specialised to the function functor (I've removed the last pair of brackets)
fmap :: (a -> b) -> (r -> a) -> r -> b
So first the value of type r (the third argument) needs to be transformed into a value of type a (by the r -> a function), so that the a -> b function can transform it into a value of type b (the result).
the type of fmap in Functor is:
fmap :: Functor f => (a -> b) -> f a -> f b
it looks like ,first apply function (a -> b) to the parameter of f a
to create a result of type b, then apply f to it, and result is f b
That is the type of fmap, but your interpretation of what that type means is wrong.
You seem to assume that f a has one parameter, and that that parameter has type a.
Consider xs :: [a]:
Perhaps xs = [].
Perhaps xs = [x1].
Perhaps xs = [x1, x2].
...
The type f a is a functor f with a single type parameter a. But values of type f a do not necessarily take the form F x, as you can see from the first and third cases above.
Now consider fmap f xs:
Perhaps fmap f xs = [].
Perhaps fmap f xs = [f x1].
Perhaps fmap f xs = [f x1, f x2].
...
We don't necessarily apply f at all (first case)! Or we might apply it more than once (third case).
What we do is replace the things of type a, with things of type b. But we leave the larger structure intact --- no new elements added, no elements removed, their order is left unchanged.
Now let's think about the functor (c ->). (Remember, a functor takes one type parameter only, so the input to (->) is fixed.)
Does a c -> a even contain an a? It might not contain any as at all, but it can somehow magic one out of thin air when we give it a c. But the result from fmap has type c -> b: we only have to provide a b out of that when we're presented with a c.
So we can say fmap f x = \y -> f (x y).
In this case, we're applying f on demand --- every time the function we return gets applied, f gets applied as well.
It needs to be defined that way to make the types work out. As you pointed out, the type of fmap is:
fmap :: Functor f => (a -> b) -> f a -> f b
Let's consider the case when the functor f is ((->) c)
(Note: we'd actually like to write this as (c ->), i.e. functions from c, but Haskell doesn't allow us to do this.)
Then f a is actually ((->) c a), which is equivalent to (c -> a), and similarly for f b, so we have:
fmap :: (a -> b) -> (c -> a) -> (c -> b)
i.e. we need to take two functions:
f :: a -> b
g :: c -> a
and construct a new function
h :: c -> b
But there's only one way to do that: you have to apply g first to get something of type a, and then apply f to get something of type b, which means that you have to define
instance Functor ((->) c) where
fmap f g = \x -> f (g x)
or, more succinctly,
instance Functor ((->) c) where
fmap = (.)
fmap for (->) is defined like fmap = (.).
So, (fmap f g) x is (f . g) x is f (g x). In your case (*3) ((+100) 1), which equals 3 * (100 + 1) which results in 303.
In order to form a function type, you need 2 kind parameters for (->), that is the single input argument type and the return type.
A Functor can only take 1 type parameter, so you have to nail down the input argument type(since it's the first one from left to right), which makes the return type of the function to be the type parameter of the Functor.
So for function (the Functor) a->b, you need to give fmap a function ff of type b->xxx other than a->xxx to work, and that means the function ff can only be applied after a->b is apply.