The function const
is defined in Prelude as:
const x _ = x
In GHCi, when I tried
Prelude> const 6 5 ->
Chuck is right, function application in Haskell is left associative, meaning that a function invocation like f a b c
is equivalent to (((f a) b) c)
. Remember, in Haskell you should always practice looking at types of functions and trying to infer what a function can and can't do based on its type. At first you might fail to deduce anything from a function type, but with more experience type information will become indispensable.
What is the type of const
? Enter :t const
in GHCi. It will return const :: a -> b -> a
. a
and b
are type variables, meaning that const will accept an argument of any type. As 1st and 2nd arguments have different types, you can pass practically everything to the function:
const 1 2 -- returns 1
const 'a' 1 -- returns 'a'
const [1,2,3] "a" -- returns [1,2,3]
There might've been specific typeclass constraints on type variables of const
that would prevent passing functions, like Num
or Ord
, because a function isn't an instance of these typeclasses. In other words, a function doesn't behave as a number or an ordered thing, so f + g
or f < g
don't make sense. But const
has no typeclass constraints that would stop us from passing functions as arguments. Remember that Haskell supports higher-order functions? This means that Haskell's functions can accept and return other functions. Therefore:
const (+) (*) -- returns (+)
const head tail -- returns head
const id 2 -- returns id
const
just ignores the 2nd argument and returns whatever was passed as a 1st argument, be it a Char, String, Integer, Maybe, [], some very complex algebraic data type, or even a function.
If the type of const
is a -> b -> a
, can you guess the type of const 'a'
without finding it out without typing :t const 'a'
in GHCi? To find out a type of const 'a'
, substitute the type of the 1st argument in place of all same type variables, then remove the first argument from the type.
a -> b -> a
: original typeChar -> b -> Char
: substitute new type in type variables ab -> Char
: the type of a new function by removing the 1st argument from type declarationWhat is the type of const id
then?
a -> b -> a
: original type(a -> a) -> b -> (a -> a)
: substitutionb -> (a -> a)
: resulting type (first argument removed)b -> a -> a
: same as above, ->
operator is right-associativeExercise:
const (+)
, const head
, const tail
, const (++)
, const map
You seem to be thinking that this is equivalent to const (id 6) 5
, where id 6
evaluates to 6, but it isn't. Without those parentheses, you're passing the id
function as the first argument to const
. So look at the definition of const
again:
const x _ = x
This means that const id 6 = id
. Therefore, const id 6 5
is equivalent to id 5
, which is indeed 5.
Functions can also be parameters to other functions. id becomes a parameter of const.
What the expression (const id 6) 5 really does is:
(const id 6) 5
(const id _) 5 -- grab the first parameter id
id 5
5
For more detail about what operators really do:
Anything in a pair of brackets would be treated as a whole expression (but it doesn't mean it will be calculated first). For example: (map (1+) ), (\x -> (-) x )
Prefix operators bind stronger than infix operators
The left-most prefix operator in an expression would be treated as a function which grabs parameters (including other prefix operators) in an expression from left to right until facing infix operators or the end of line. For example, if you type map (+) id 3 const + 2 in GHCi, you will get an error that says "The function `map' is applied to four arguments..." because map grabs (+), id, 3 and const as parameters before the infix operator +.