3
votes

I'm trying to understand the type of the expression const (++) in Haskell. I know the individual types of const and (++) and I know that you can leave out parameters in order to return partially applied functions.

If I type :t const (++) I get const (++) :: b -> [a] -> [a] -> [a]. The way I think is that (++) wants two lists (I know however that all functions in Haskell are curried functions that actually just take one argument) and returns a list. This list is then the first argument to the const function, which waits for one more argument. So, I thought the type would be const (++) :: [a] -> [a] -> b -> [a].

But for example: const (++) 1 "hello" "you" returns "helloyou". How come the thing that is returned from the const operation is not the first argument, according to the definition of const which is const x _ = x? Where in my thought process am I incorrect?

2

2 Answers

6
votes

How come the thing that is returned from the const operation is not the first argument

It is. The first argument to const is (++). So the result of the operation const (++) 1 is in fact (++), which is the first argument. So const (++) 1 is (++), meaning const (++) 1 "hello" "you" is (++) "hello" "you" and that is "helloyou".

2
votes
(++) :: [a] -> [a] -> [a]
      ≡ ([a] -> [a] -> [a])

const :: c -> b -> c

Now, in const (++), you want to give (++) as an argument to const. The argument to const should have type c, so you unify that with the type of (++)

     c  ~  ([a] -> [a] -> [a])

and get the specialised version

const :: ([a] -> [a] -> [a]) -> b -> ([a] -> [a] -> [a])

If that looks confusing, consider the simpler case of const 1. If the 1 has type Int, then we must have c ~ Int and in that case

const :: Int -> b -> Int

Because function arrows are right-associative, the (++)-specialisation can also be written

const :: ([a] -> [a] -> [a]) -> b -> [a] -> [a] -> [a]

Now if you actually apply that to (++), you saturate the function argument and end up with

const (++) :: b -> [a] -> [a] -> [a]