Listy zbudowane są z wielu elementów tego samego typu. Pustą listę oznacza się symbolem [], natomiast operator :: doczepia na początku listy nowy element. Można je tworzyć na dwa sposoby; rekurencyjnie -- doczepiając do pustej listy kolejne elementy, lub w równoważny sposób -- podając w kwadratowym nawiasie elementy oddzielone średnikami. Spójrzmy na poniższy przykład:

# [1;2;3;4;5];;
- : int list = [1; 2; 3; 4; 5]

# 1 :: 2 :: 4 :: 5 :: [];;
- : int list = [1; 2; 4; 5]

# ['a'; 'b'; 'c'; 'd'];;  
- : char list = ['a'; 'b'; 'c'; 'd']

# [];;                    
- : 'a list = []

Typem ogólnym listy jest 'a list, gdzie 'a jest "typem polimorficznym", który oznacza "dowolny typ". Szczególnymi przypadkami list może być lista intów: int list lub znaków: char list. Do łączenia dwóch list w jedną używany jest operator '@'.

Jeśli OCaml nie będzie w stanie określić typu któregoś z argumentów funkcji, stworzy funkcję polimorficzną, która może przyjąć argument o dowolnym typie. Wiele z funkcji z biblioteki standardowej jest właśnie tak zbudowana. Dla przykładu rozważmy funkcję List.map:

# List.map;;                          
- : ('a -> 'b) -> 'a list -> 'b list = <fun>

# List.map (fun a -> a + 5) [1; 2; 3];; 
- : int list = [6; 7; 8]

Funkcja ta przyjmuje dwa argumenty: Funkcję ('a -> 'b) przyjmującą jeden argument dowolnego typu, i zwracającą argument innego typu (lub tego samego, ale niekoniecznie) oraz 'a list, czyli listę tego samego typu, który przyjmuje funkcja i zwraca listę elementów ('b list) zwracanych przez funkcję. Trochę to było skomplikowane ale wybrnęliśmy.

W tym przykładzie również możemy zauważyć zastosowanie funkcji anonimowej: (fun a-> a+5), która została stworzona specjalnie na potrzeby wywołania List.map -- nie posiada własnej nazwy i nie może być później użyta ponownie.