Apply and Applicative


#1

Reading Typeclassopedia, I just found out about Apply and have some questions.

1. <*> vs <.>

also included .> vs *>, <. vs <* and liftF2 vs liftA2

Why are there multiple version of operations that seem like exactly the same (to me)?

λ> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
λ> :t (<.>)
(<.>) :: Apply f       => f (a -> b) -> f a -> f b

and Apply is already a Functor

λ> :i Apply 
class Functor f => Apply (f :: * -> *) where
  (<.>) :: f (a -> b) -> f a -> f b
  (.>) :: f a -> f b -> f b
  (<.) :: f a -> f b -> f a
  liftF2 :: (a -> b -> c) -> f a -> f b -> f c
  {-# MINIMAL (<.>) | liftF2 #-}

λ> :i Applicative 
class Functor f => Applicative (f :: * -> *) where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b
  GHC.Base.liftA2 :: (a -> b -> c) -> f a -> f b -> f c
  (*>) :: f a -> f b -> f b
  (<*) :: f a -> f b -> f a
  {-# MINIMAL pure, ((<*>) | liftA2) #-}

What is the different between <$> and <.> why can’t just reuse <,> instead of introducing <*>?

Why it is not the case that the following (not sure about the syntax, hope you get the idea)

class Functor f, Apply f => Applicative f where
    pure :: a -> f a

reuse <.>, .>, <. and liftF2 and be able to free 4 operators to use else where with different meaning?

2. Why is the word Apply?

What is the origin of the word Apply in this context?
Is it the same as Applicative model mentioned in Backus’s Paper


#2

I think this is mostly historical. Even the Applicative superclass of Monad is very recent and not everyone was happy with that. It can get quite annoying having to implement all superclasses before you can implement the class you’re really interested in. There is a reason that the numeric hierarchy is not done properly like numhask or numeric-prelude. I would love to see a proposal that improves the usability of those libraries.


#3

Your syntax is almost correct. Apply could be (and some people think that it should be) a valid superclass of Applicative and then the Applicative typeclass definition could look like this:

class Apply f => Applicative f where
    pure :: a -> f a

NOTE: You don’t need to specify Functor here because it’s already implied by Apply.

In fact, in PureScript Applicative is already implemented with the Apply superclass:

But as @jaror mentioned, the reasons for having the current typeclass hierarchy in Haskell are mostly historical. PureScript appeared many years later, and it has the opportunity to implement things differently. But changing the hierarchy of standard typeclasses in Haskell would be a long and painful process…