Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lists

Lists in milang are singly-linked cons cells, declared in the prelude as List = {Nil; Cons head tail}. The bracket syntax is sugar that desugars into this representation.

Constructing Lists

nums = [1, 2, 3, 4, 5]
empty = []
consed = 10 : 20 : 30 : []
build =  {target = c, os = linux, arch = x86_64}
nums = [1, 2, 3, 4, 5]
empty = []
consed = [10, 20, 30]

[] is Nil, and [1, 2, 3] desugars to Cons 1 (Cons 2 (Cons 3 Nil)). The : operator (cons) is right-associative.

Use range to generate a sequence:

a = range 1 6
b = range 1 11
build =  {target = c, os = linux, arch = x86_64}
a = [1, 2, 3, 4, 5]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Accessing Elements

head, tail, last, and init all return Maybe values — Just x on success, Nothing on an empty list. at returns Maybe for index access.

xs = [10, 20, 30]
a = head xs
b = tail xs
c = last xs
d = init xs
e = at xs 1
f = head []
build =  {target = c, os = linux, arch = x86_64}
xs = [10, 20, 30]
a = Just {val = 10}
b = Just {val = [20, 30]}
c = Just {val = 30}
d = Just {val = [10, 20]}
e = Just {val = 20}
f = Nothing {}

len returns the number of elements:

a = len [1, 2, 3]
b = len []
build =  {target = c, os = linux, arch = x86_64}
a = 3
b = 0

Transforming

map

Apply a function to every element:

doubled = map (\x -> x * 2) [1, 2, 3, 4, 5]
build =  {target = c, os = linux, arch = x86_64}
doubled = [2, 4, 6, 8, 10]

filter

Keep elements satisfying a predicate:

evens = filter (\x -> x % 2 == 0) [1, 2, 3, 4, 5, 6]
build =  {target = c, os = linux, arch = x86_64}
evens = [2, 4, 6]

fold

Left-fold with an accumulator:

total = fold (+) 0 [1, 2, 3, 4, 5]
build =  {target = c, os = linux, arch = x86_64}
total = 15

reverse

backwards = reverse [1, 2, 3, 4, 5]
build =  {target = c, os = linux, arch = x86_64}
backwards = [5, 4, 3, 2, 1]

take / drop

front = take 3 [1, 2, 3, 4, 5]
back = drop 3 [1, 2, 3, 4, 5]
build =  {target = c, os = linux, arch = x86_64}
front = [1, 2, 3]
back = [4, 5]

zip

Pair up elements from two lists:

pairs = zip [1, 2, 3] [10, 20, 30]
build =  {target = c, os = linux, arch = x86_64}
pairs = [[1, 10], [2, 20], [3, 30]]

enumerate

Produce [index, value] pairs:

indexed = enumerate ["a", "b", "c"]
build =  {target = c, os = linux, arch = x86_64}
indexed = [[0, a], [1, b], [2, c]]

Combining Lists

joined = concat [1, 2] [3, 4]
appended = push [1, 2, 3] 4
build =  {target = c, os = linux, arch = x86_64}
joined = [1, 2, 3, 4]
appended = [1, 2, 3, 4]

join concatenates a list of strings with a separator:

csv = join ", " ["alice", "bob", "carol"]
build =  {target = c, os = linux, arch = x86_64}
csv = alice, bob, carol

Querying

xs = [1, 2, 3, 4, 5]
a = sum xs
b = product xs
c = any (\x -> x > 4) xs
d = all (\x -> x > 0) xs
e = contains xs 3
f = contains xs 99
build =  {target = c, os = linux, arch = x86_64}
xs = [1, 2, 3, 4, 5]
a = 15
b = 120
c = 1
d = 1
e = 1
f = 0

Pipelines

Lists work naturally with the pipe operator for readable data processing:

result = range 1 11 \
  |> filter (\x -> x % 2 == 0) \
  |> map (\x -> x * x) \
  |> sum
build =  {target = c, os = linux, arch = x86_64}
result = 220

Pattern Matching on Lists

Match by exact length with [a, b, c], or match head and tail with [first, ...rest]:

xs = [10, 20, 30, 40]
result = xs ->
  [a, b, ...rest] = a + b
  [] = 0
build =  {target = c, os = linux, arch = x86_64}
xs = [10, 20, 30, 40]
result = 30

Recursive functions often pattern-match to walk a list:

mySum xs = xs ->
  [x, ...rest] = x + mySum rest
  [] = 0