

> {-# LANGUAGE Rank2Types,ExistentialQuantification #-}





X



forall a . (a -> X,a) -> X



eval



> eval (f,x) = f x





f



forall a . (a -> X,a) -> X



g



f (x,g y) = f (x . g,y)



f

forall a . (a -> X,a) -> X

X

a

a

f

a

a->X

f

h . eval

h

eval (x,g y) = eval (x.g,y)

f



forall a . (a -> X,[a]) -> X



f

g



f(x,map g y) = f(x . g,y)



[a]

fmap

a -> X

fmap

forall a . S a a -> X

S

S a

S a b

b

a



> class Difunctor h where

> lmap :: (b -> a) -> h a c -> h b c

> rmap :: (c -> d) -> h a c -> h a d







lmap (f . g) = lmap g . lmap f

rmap (f . g) = rmap f . rmap g





> data Ex1 x a b = Ex1 (a -> x) b



> instance Difunctor (Ex1 x) where

> lmap f (Ex1 g x) = Ex1 (g . f) x

> rmap f (Ex1 g x) = Ex1 g (f x)



> data Ex2 x a b = Ex2 (a -> x) [b]



> instance Difunctor (Ex2 x) where

> lmap f (Ex2 g x) = Ex2 (g . f) x

> rmap f (Ex2 g x) = Ex2 g (map f x)







> type DiNatural s x = forall a . (s a a -> x)







f . lmap g == f . rmap g



s

g

lmap

rmap

X

f :: s a a -> X

s

f

g



f . lmap g == f . rmap g



s

Difunctor

X

DiNatural s X

f . fmap g = fmap g . f

s

Y

i :: s a a -> Y

f :: s a a -> X

X

f = h . i

Y

s

(a -> X,a)

X



> data Coend s = forall a . Coend (s a a)





t

Coend (Ex1 t)



> iso :: Coend (Ex1 t) -> t

> iso (Coend (Ex1 f x)) = f x



> iso' :: t -> Coend (Ex1 t)

> iso' x = Coend (Ex1 (const x) ())





iso

iso'

forall a . s a a -> X

a

uncurry

Abstract nonsense warning: my goal here is simply to understand what the definition of a coend means in the context of Haskell.Pick a type. Let's call it. Now consider the typeWhat can we say about elements of this type? There's an obvious example of such a function,that applies the first element of the pair to the second.It's also easy to construct others. What property do they all share? Well there's a nice way to answer this question. We can use Janis Voigtländer's Free Theorem Generator . After a bit of simplification it tells us that ifis inthen for any compatibleWe can apply any function we like to the second argument and we get exactly the same result by pre-composing with the first argument.This is a pretty strong property - it puts a big constraint on whatcan do. It holds because any function of typemaps to a typethat makes no reference to the quantified. It can't let any information about the typeescape. And this means thathas to somehow eliminate an element ofand and element of. There's only one non-trivial way to do that: provide the former to the latter as a function argument. Somust factor asfor some function. The free theorem comes from the fact that. Or,could be the constant function, but that still factors in the same way.Let's try something slightly more complex. Consider the typeAgain we can ask the free theorem generator to give us a property. We're told that ifis of this type, then for any compatibleThe crucial point this time is that in order to eliminate thewe have to useto apply the function of type. So any function of this type must factor through, and that's why the free theorem follows.Now it's time to put this in a more general framework. We can write both of the above examples as elements of typewhereis some type constructor. In both cases we also have thatis a functor. But it's also a cofunctor in its first argument. Intuitively this says thatcontains or produces's but consumes's. Here's a class to express this:(I made up the word Difunctor.)For (co)functoriality we insist on the lawsWe can make both of the examples above instances:Our free theorems were essentially about this type:and in both cases the free theorem could be written asThis is a highly non-trivial result. Look at the preconditions for this theorem: they say something about each of the arguments toindividually. And yet we deduce that the two arguments are in fact intimately connected. We can applyusing eitherorand get the same result. This property is known as dinaturality. More precisely, if for some, whereis a difunctor, thenis dinatural if for all compatibleWe have this theorem: ifis an instance of theclass (obeying its laws) then for any, elements ofare dinatural.(Compare with the definition of naturality:.)I'm tempted to call this "Dinaturality for Free" but there's already a paper by that name and I don't know what it's about. And note that I only claim it's a theorem. I don't actually know how to prove this uniformly for all difunctors, but I'd stake a beer on it. At least as long as we don't do any weird haskell coding (so our free theorems are always valid) and as long as we restrict ourselves to functions that always terminate.In the examples I gave above the reason why this holds is related to the fact that any function of the given type can be factored as something following an evaluation type function. More generally, ifis a dinatural then if there is a single, and function, such that every function, for any, can be factored as, thenis said to be the coend ofThere are different approaches to computing a coend. Above I've used inspection. The coend ofis. But there's also a kind of cheating approach where we can use an existential type to get the type uniformly for all dinaturals:For an explanation of why that works, see Edward Kmett's post on Kan Extensions . For this example, this means we expect the typesandto be isomorphic. Here is the isomorphism and its inverse:I'll leave the proof thatandare mutual inverses to you.I hope that gives some idea of what a coend is. Informally it captures the method by which a dinatural transformation of typeis able to eliminate the quantified. If you look through the Haskell libraries you'll find many dinaturals (or at least things that can be made dinatural through the use of).This code and description was inspired by the discussion at nLab