
Cale Gibbard wrote:
Hello, just thought I'd finally weigh in on this thread, having given it a little thought.
While there are a few nice examples of instances of Compositor, I think I'd prefer to have (.) be what is currently fmap. Note that it generalises ordinary function composition through the functor ((->) e). Also you get a restricted form of the Arrow case through the inclusion of an instance of Functor for ((~>) e) when (~>) is an Arrow.
The only argument for having (.) = fmap that I can think of is that the types happen to work out. Using (.)/(○) like this is, as far as I know, not standard usage in any way. In category theory (.) is composition of morphisms, which is exactly what is proposed for the Category class. You have laws like
id . f = f . id = f Of which only the first halve makes sense for fmap.
Function composition forms a monoid, this is still true for composition of morphisms, not for functor application. Your argument for seeing (.) as composition on other functors such as lists is that these functors can all be considered a kind of 'functions'. For instance a list is a partial function from the naturals, a pair is a function from unit, etc. I don't think this holds for all functors. What about, say, State or STM?
I've tried this out for a while, and it is actually rather nice to use in many cases. Functor application is common enough that having a one-character representation for it is great.
Could you give an example where (.) = fmap actually makes sense for a non-reader functor, and has a clear advantage in readability and understandability over fmap/map/(<$>)? With the Category definition you have for instance functional references:
set (head . fst) :: a -> ([a],c) -> ([a],c) set (head . fst) 'a' ("dbc",123) == ("abc",123)
And bijections:
inverse (f . g) == inverse g . inverse f
To summarize: fmap may generalize the type of (.), but that is about all it does. This usage is completely non-standard and, at least to me, unintuitive. Twan