Search code examples
haskelltypestype-constructor

What does '((->) a)' mean?


I've seen this type before without knowing what it means. Does it mean something and/or does it have a name?

Prelude> :m Data.Functor
Prelude Data.Functor> :t flip . (flip (<$>))
flip . (flip (<$>))
:: Functor ((->) b) => (b -> a) -> b -> (a -> c) -> c

Solution

  • To add to Matt Fenwick and josefg's more technical answers, the ((->) a can be read as the type constructor that forms values that depend on an a. One example: suppose you have teams whose membership varies over time. One possible way to represent this is like this:

    -- | The type of a's that depend on a point in time, using t as the timeline type.
    type Historical t a = t -> a
    
    observe :: Historical t a -> t -> a
    observe = ($)
    
    -- | The membership of a team is a list of persons whose composition can change
    -- from day to day.
    membership :: Team -> Historical Day [Person]
    membership = ...
    

    ((->) a) is a Functor, Applicative and Monad, which means that the type class operations are available, and they have very useful interpretations when used with Historical t.

    First example: fmap applies a function to a time-dependent value. So for example,

    -- The number of persons in a Team, depending on the Day:
    membershipCount :: Team -> Historical Day Int
    membershipCount = fmap length . membership
    

    The Applicative <*> operation gives you simultaneity:

    -- The joint membership of team1 and team2, depending on the Day:
    (++) <$> membership team1 <*> membership team2 :: Historical Day [Person]
    

    Though actually, since we have instance Monoid [a] and instance Monoid m => Monoid t -> m, the previous example can be written like this:

    import Data.Monoid
    
    membership team1 ++ membership team2
    

    Monad gives you composition:

    personToManager :: Person -> Historical Day Manager
    personToManager = ...
    
    managerToVP :: Manager -> Historical Day VP
    managerToVP = ...
    
    personToVP :: Person -> Historical Day VP
    personToVP p = personToManager p >>= managerToVP
    

    Note also that ((->) r is exactly the same as the Reader r monad. If you understand the code above you pretty much understand Reader.


    EDIT: I should clarify that time-dependent values is just one use of the function/Reader monad. There are other uses; the classic example use case of the Reader monad is to thread configuration values through a computation. It's got rather more uses than just that, as the example above shows.