kedebug
kedebug

Reputation: 362

How can I understand ":t ((==) <*>)" in Haskell?

I'm new to Haskell, here get in trouble with <*> :

((==) <*>) :: Eq a => (a -> a) -> a -> Bool

How can I understand this and how it can be deduced?

Upvotes: 27

Views: 3324

Answers (1)

Gabriella Gonzalez
Gabriella Gonzalez

Reputation: 35089

Disclaimer: That's not idiomatic Haskell code.

The first thing that takes precedence is the "operator section" of <*>. When you see an operator only applied to one argument that's called a section. Here's an example of a more common operator section:

(1 +) :: Int -> Int

That's a function that partially applies + to 1, leaving room for one last argument. It's equivalent to:

\x -> 1 + x

So in your code sample the <*> is partially applied to (==), so we'll expand that out to:

((==) <*>)

= \g -> (==) <*> g

Next off you need to understand what the <*> is doing. This is a member of the Applicative type class:

class (Functor f) => Applicative f where
    pure  :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

This means that <*> is overloaded to work on any type that implements Applicative. One instance of the Applicative type is ((->) r):

instance Applicative ((->) r) where
    pure  :: a -> ((->) r) a
    (<*>) :: (->) r (a -> b) -> (->) r a -> (->) r b

The parentheses around the (->) mean that is being used in prefix form (which is necessary for syntactic reasons when defining class instances like this one). If you expand it out to infix form you get:

instance Applicative ((->) r) where
    pure  :: a -> r -> a
    (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)

In your specific example, the first argument of <*> is the (==) operator, which has the following type:

(==) :: Eq e => e -> e -> Bool

Therefore, if we pass it to the (<*>) the compiler can deduce more about the types of r, a, and b in the signature for (<*>):

 (<*>) ::        (r -> a -> b   ) -> (r -> a) -> (r -> b)
 (==)  :: Eq e => e -> e -> Bool
                  |    |    |
                  |    |    +-> `b` must be `Bool`
                  |    |
                  |    +------> `a` must be `e`
                  |
                  +-----------> `r` must also be `e`

So when we supply (==) as the first argument of (<*>) we get this inferred type:

((==) <*>) :: Eq e => (e -> e) -> (e -> Bool)

You can leave off the right parentheses because (->) is right-associative, and change e to a to give the final signature you got:

((==) <*>) :: Eq a => (a -> a) -> a -> Bool

But what is this actually doing? To understand that we need to see how (<*>) is defined for the Applicative instance of ((->) r):

(f <*> g) r = f r (g r)

If we replace f with (==) we get:

((==) <*> g) r = (==) r (g r)

When we surround (==) with parentheses, that means we are using it in prefix notation. This means that if we remove the parentheses and change it back to infix notation we get:

((==) <*> g) r = r == (g r)

This is equivalent to:

((==) <*>) = \g r -> r == g r

So that means that your function takes two parameters: g and r, and then sees if r equals g r.

Upvotes: 58

Related Questions