Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 443
kedebug Avatar asked Sep 15 '13 14:09

kedebug


People also ask

What does () mean in Haskell?

() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .

What does apostrophe mean in Haskell?

In Haskell it is just another character to distinguish identifiers and the identifier is then called fold prime , but it is commonly used in the same way as it used in mathematics.

What is cons operator in Haskell?

The : operator is known as the "cons" operator and is used to prepend a head element to a list. So [] is a list and x:[] is prepending x to the empty list making a the list [x] . If you then cons y:[x] you end up with the list [y, x] which is the same as y:x:[] .

Does Haskell use call by name?

Call by needHaskell is a well-known language that uses call-by-need evaluation.


1 Answers

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.

like image 170
Gabriella Gonzalez Avatar answered Nov 02 '22 20:11

Gabriella Gonzalez