As well as meaning 'increment', or 'up-karma', in the above cited contexts, ++ is also the symbol used in Haskell as the list concatenation operator.
As defined recursively in the standard prelude, the operator is right associative, and of precedence just below that of + and -, and above the comparison operators ==, /= etc:
infixr 5 ++
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x:(xs++ys)
Line by line breakdown (I did say 'In plain English', but Oolong laughed at me):
-
infixr 5 ++
-
Defines ++ as a right associative infix operator, with precedence (an arbitrary integer) of 5. (the comparison operators have precedence 4, addition and subtraction precedence 6)
-
(++) :: [a] -> [a] -> [a]
-
Defines the type of the ++ operator: a function which takes two lists (of arbitrary but identical type elements), and returns a list of the same type. Or, equivalently, a function which takes a list, and returns a function which takes a list and returns a list... partial application being one of Haskell's specialties.
-
[] ++ ys = ys
-
The recursive base case. Bear in mind that the operator is right-associative. Defining the concatenation of the empty list with some other arbitrary list is, by definition, the other list.
-
(x:xs) ++ ys = x:(xs++ys)
-
The meat of the recursive definition. Where the first list to be concatenated is known to have some element, x, (ie. it is not the empty list) consed with a (possibly empty) list of other elements, xs, the concatenation of the two lists is x consed with the concatenation of the xs and the original second list. Since the left hand side operand of the concatenation in the result is one element smaller (that element being 'x') than that it the pattern on the left hand side, the 'xs' list will tend towards the empty list, at which point the expression matches with the base case and the evaluation is complete.
As an example... let's concatenate [1, 2] with [3, 4]... go on, you know you want to.
[1, 2] ++ [3, 4]
== (1:[2]) ++ [3, 4] (list syntax change)
== 1:([2] ++ [3, 4]) (recursive case of ++)
== 1:((2:[]) ++ [3,4]) (list syntax change)
== 1:2:([3,4]) (base case of ++)
== [1, 2, 3, 4] (list syntax change)
So there we go, [1, 2] ++ [3, 4] == [1, 2, 3, 4]. QED