2008/4/24 Dan Doel <[EMAIL PROTECTED]>: > On Thursday 24 April 2008, Wolfgang Jeltsch wrote: > > I don't think that this is reasonable. (.) corresponds to the little > > circle in math which is a composition. So (.) = (<<<) would be far better. > > Were I building a library, this might be the direction I'd take things. > They're two incompatible generalizations, and you have to decide which is > more important to you. > > For instance, you can generalize from arrows into categories (with objects in > *): > > class Category (~>) where > id :: a ~> a > (.) :: (b ~> c) -> (a ~> b) -> (a ~> c) > > And, of course, from this, you get the usual meanings for (->): > > instance Category (->) where > id x = x > (f . g) x = f (g x) > > An example of a Category that isn't an Arrow (I think) is: > > newtype Op (~>) a b = Op { unOp :: b ~> a } > > instance Category (~>) => Category (Op (~>)) where > id = Op id > -- (.) :: (b <~ c) -> (a <~ b) -> (a <~ c) > (Op f) . (Op g) = Op (g . f) > > type HaskOp = Op (->) > > (Why is this even potentially useful? Well, if you define functors with > reference to what two categories they relate, you get (pardon the illegal > syntax): > > map :: (a ~1> b) -> (f a ~2> f b) > > Which gives you current covariant endofunctors if (~1>) = (~2>) = (->), but > it > also gives you contravariant endofunctors if (~1>) = (->) and (~2>) = Op > (->). Is this a useful way of structuring things in practice? I don't know.) > > Now, going the (.) = map route, one should note the following Functor > instance: > > instance (Arrow (~>)) => Functor ((~>) e) where > -- fmap :: (a -> b) -> (e ~> a) -> (e ~> b) > fmap f g = arr f <<< g > > So, in this case (.) is composition of a pure function with an arrow, but it > does not recover full arrow composition. It certainly doesn't recover > composition in the general Category class above, because there's no operation > for lifting functions into an arbitrary Category (think Op: given a function > (a -> b), I can't get a (b -> a) in general). > > (At a glance, if you have the generalized Functors that reference their > associated Categories, you have: > > map (a ~1> b) -> (e ~3> a) ~2> (e ~3> b) > > so for (~1>) = (~3>), and (~2>) = (->), you've recovered (.) for arbitrary > categories: > > instance (Category (~>) => Functor ((~>) e) (~>) (->) where > map f g = f . g > > so, perhaps with a generalized Functor, you can have (.) = map *and* have (.) > be a generalized composition.) > > Now, the above Category stuff isn't even in any library that I know of, would > break tons of stuff (with the generalized Functor, which is also kind of > messy), and I haven't even seriously explored it, so it'd be ridiculous to > request going in that direction for H'. But, restricted to the current > libraries, if you do want to generalize (.), you have to decide whether you > want to generalize it as composition of arrows, or as functor application. > The former isn't a special case of the latter (with the current Functor, at > least). > > Generalizing (.) to Arrow composition seems more natural to me, but > generalizing to map may well have more uses. > > -- Dan
Right, my own preference in this regard is to generalise in the direction that (<<<) would be a method of Category, which is a generalisation of Arrow. We currently at least have way more Functor instances than Category instances, so it seems sensible to pick the shorter notation for the more common case, but I do strongly think we should start pushing things in this direction. These are all really nice, extremely general ideas which can make libraries nicely uniform. - Cale _______________________________________________ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime