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?
() 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 () .
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.
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:[] .
Call by needHaskell is a well-known language that uses call-by-need evaluation.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With