HandsomeGorilla
HandsomeGorilla

Reputation: 625

What does the use of a colon between symbols in a parameter in a Haskell function definition do?

I've been reading through Real World Haskell and I've come across an interesting solution to an exercise in chapter 2.

The exercise asks the reader to construct a function that behaves similarly to Haskell's drop. One solution looks like this:

lastButOne :: [a] -> a
lastButOne (x:xs) = if length xs == 1
                    then x
                    else lastButOne xs

With an improved version looking like this:

lastButOne :: [a] -> a
lastButOne (x1:[x2]) = x1
lastButOne (x:xs) = lastButOne xs

I'm having quite a bit of trouble understanding what the infix colon is doing here. Can somebody give me an idea of how I should be reading this?

From what I understand, elem:[b] tells Haskell to prepend elem to [b].

But let's suppose I define a function like lastButOne (x:xs). Then let's suppose I have a list testCase = [p,q..r]. Would I be right in presuming that lastButOne would treat testCase as two separate objects, i.e. [p] and [q..r]?

If that's the case, the reading the first iteration of lastButOne feels totally intuitive. But then I still don't understand how the second iteration of lastButOne works.

Upvotes: 2

Views: 1241

Answers (3)

j.i.h.
j.i.h.

Reputation: 827

The : operator is commonly referred to as cons (adopted from Lisp parlance). (x:xs) is a common Haskell pattern match, where (x:xs) is an [a], x is the head / first element of the list (an a), and xs is the tail / rest of the list (an [a] or list of as).

Prelude> let a = (1:2:3:[])
Prelude> let b = (1:[2,3])
Prelude> a
[1,2,3]
Prelude> b
[1,2,3]

Upvotes: 0

HandsomeGorilla
HandsomeGorilla

Reputation: 625

LIGHTBULB.

lastButOne :: [a] -> a
lastButOne (x1:[x2]) = x1
lastButOne (x:xs) = lastButOne xs

This code works like so: Haskell checks the pattern (x1:[x2]) against the object passed to lastButOne. (x1:[x2]) is a pattern matching a singleton list prepended by an item of the same type as x2. A list like this [1,2] fits this pattern and could be written as 1:[2], while a list like this [1,2,3] does not fit the pattern. Since the first pattern match fails, Haskell falls through to the 'catch-all' pattern, x:xs.

Upvotes: 0

Code-Apprentice
Code-Apprentice

Reputation: 83567

lastButOne (x:xs)... has only one parameter, as you can see from the function's type. The (x:xs) is a pattern which matches a list with at least one element. The first element is named x and the rest of the list is named xs.

Upvotes: 4

Related Questions