Language:

CoffeeScript


Concept:

List comprehension

Headline

A language construct for list processing

Illustration

Mapping over a list

Suppose you want to map over a list of numbers to increment each number. The following list comprehension implements this requirement:

> [ x+1 | x <- [1,2,3,4,5] ]
[2,3,4,5,6]

The expression after the bar "|" is the generator for elements x. The expression before the bar computes the element of the resulting list from the generated elements. The Map function actually models such element-wise mapping. Thus, the list comprehension could also be expressed as follows:

> map (\x -> x + 1) [1,2,3,4,5]
[2,3,4,5,6]

Filtering a list

Suppose you want to filter a list of numbers to only keep odd numbers. The following list comprehension implements this requirement:

> [ x | x <- [1,2,3,4,5], odd x ]
[1,3,5]

There are two expressions after the bar. The first one is a generator for elements x, the second is a guard to impose a condition of generated elements. The Filter function actually models filtering according to a guard (i.e., a predicate). Thus, the list comprehension could also be expressed as follows:

> filter odd [1,2,3,4,5]
[1,3,5]

Multiple generators and guards

List comprehensions can use multiple generators and guards, the scope of the generators extends to the subsequent generators and guards. For instance, we may collect all combinations of pairs of elements drawn from two separate lists as follows:

> [ (x,y) | x <- [1,2,3], y <- ['a','b'] ]
[(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]

Let us compute the sum of all possible pairs with elements drawn from one list, where a guard is applied to reject pairs of identical elements:

> let sample = [1,2,3,4,5]
e> [ x + y | x <- sample, y <- sample, x /= y ]
[3,4,5,6,3,5,6,7,4,5,7,8,5,6,7,9,6,7,8,9]


Concept:

Loop

Headline

the description of repeated execution in a program


Concept:

Pattern matching

Headline

Matching values against patterns to bind variables

Description

Pattern matching may be concerned with different kinds of types, e.g., text or trees. In the case of text, regular expressions provide the foundation for patterns. In the case of trees and specifically in the context of functional programming, algebraic data types provide the foundation for patterns; in this case, pattern matching is concerned with case discrimination on different constructor patterns such that variables are bound in successfully matched patterns for use in expressions.

Illustration

Pattern matching in Haskell

The basics of Haskell's pattern matching are very similar to those of other functional programming languages.

Pattern matching on pairs

-- Project a pair to first component
fst :: (a,b) -> a
fst (x,_) = x

-- Project a pair to second component
snd :: (a,b) -> b
snd (_,x) = x

These two functions fst and snd are defined like this (or similarly) in the Prelude module of Language:Haskell. They are defined by pattern matching on the structure of tuples; see the the left-hand sides of the function definitions. The idea of such pattern matching is of course that variables in the pattern (on the left-hand side) can be used in the expression of the definition (on the right-hand side).

Pattern matching on lists

-- Retrieve head (first element) of a list
head :: [a] -> a
head (x:_) = x

-- Retrieve tail (all but first element) of a list
tail :: [a] -> [a]
tail (_:xs) = xs

These two functions head and tail are defined like this (or similarly) in the Prelude module of Language:Haskell. They demonstrate that non-empty lists are constructed with the cons constructor ":" from a head and a tail.

Pattern matching is particularly convenient, when functions should be defined by case discrimination on the different constructor patterns for a data type. Consider, for example, the length function (again borrowed from the Prelude); this definition consists of two equations: one for the case of an empty list and another case for non-empty lists:

-- Determine length of list
length :: [a] -> Int
length [] = 0
length (_:xs) = length xs + 1

Other forms of pattern matching

  • Pattern matching is particularly useful for user-defined algebraic data types.
  • Pattern matching is not limited to the use on left-hand sides of equations. Instead, pattern matching can also be performed through case expressions in an expression context.
  • Haskell patterns may involve so-called guards to control the selection of equations (cases) not just purely on the grounds structure but also computations on top of bound variables.
  • Haskell provides different forms of patterns to deal with laziness. This is not further discussed here.

Concept:

Syntactic sugar

Headline

Redundant additions to a programming language's syntax that aids in expressing ideas more concisely.

Illustration

Take for example, array access in Language:C:

// arr[i] is syntactic sugar for *(arr + i)
int arr[]  = {1, 2, 3};
int bitter = *(arr + 1); // no sugar
int sweet  = arr[1];     // syntactic sugar