Just learned this in Prolog, and the definition is beautiful:

append([], L, L).
append([H|T], L2, [H|L3]) :- append(T, L2, L3).

Declarative programming is way outside my normal methods of thinking — it definitely takes some getting used to. From the tutorial:

[This] illustrates a more general theme: the use of unification to build structure. In a nutshell, the recursive calls to append/3 build up this nested pattern of variables which code up the required answer. When Prolog finally instantiates the innermost variable _G593 to [1, 2, 3], the answer crystallises out, like a snowflake forming around a grain of dust. But it is unification, not magic, that produces the result.