Lists and Transformations
In this chapter you will learn:
- How to create and deconstruct lists
- The core list operations:
map,filter,foldl,foldr - Other useful list functions from the prelude
- How to combine list operations into pipelines
Creating Lists
Lists are written with square brackets and commas:
numbers: [1, 2, 3, 4, 5]
strings: ["hello", "world"]
empty: []
nested: [[1, 2], [3, 4]]
Basic List Operations
head and tail
head returns the first element; tail returns everything after it:
eu -e '[10, 20, 30] head'
10
eu -e '[10, 20, 30] tail'
- 20
- 30
Use head-or to provide a default for empty lists:
eu -e '[] head-or(0)'
0
first and second
first is an alias for head. second returns the second element:
eu -e '[:a, :b, :c] second'
b
cons
cons prepends an element to a list:
eu -e 'cons(0, [1, 2, 3])'
- 0
- 1
- 2
- 3
nil?
Test whether a list is empty:
eu -e '[] nil?'
true
count
Count the elements:
eu -e '[10, 20, 30] count'
3
Transforming Lists
map
Apply a function to every element:
eu -e '[1, 2, 3] map(inc)'
- 2
- 3
- 4
eu -e '[1, 2, 3] map(* 10)'
- 10
- 20
- 30
filter
Keep only elements satisfying a predicate:
eu -e '[1, 2, 3, 4, 5, 6] filter(> 3)'
- 4
- 5
- 6
remove
The opposite of filter -- remove elements satisfying the predicate:
eu -e '[1, 2, 3, 4, 5] remove(> 3)'
- 1
- 2
- 3
Folding
Folds reduce a list to a single value by applying a binary function across all elements.
foldl
Left fold: foldl(op, init, list) applies op from the left:
eu -e 'foldl(+, 0, [1, 2, 3, 4, 5])'
15
foldr
Right fold: foldr(op, init, list) applies op from the right:
eu -e 'foldr(++, [], [[1, 2], [3, 4], [5]])'
- 1
- 2
- 3
- 4
- 5
Slicing
take and drop
eu -e '[1, 2, 3, 4, 5] take(3)'
- 1
- 2
- 3
eu -e '[1, 2, 3, 4, 5] drop(3)'
- 4
- 5
take-while and drop-while
eu -e '[1, 2, 3, 4, 5] take-while(< 4)'
- 1
- 2
- 3
Combining Lists
append and ++
eu -e '[1, 2] ++ [3, 4]'
- 1
- 2
- 3
- 4
concat
Flatten a list of lists:
eu -e 'concat([[1, 2], [3], [4, 5]])'
- 1
- 2
- 3
- 4
- 5
mapcat
Map then flatten (also known as flatMap or concatMap):
eu -e '["ab", "cd"] mapcat(str.letters)'
- a
- b
- c
- d
Checking Lists
all-true? and any-true?
eu -e '[true, true, false] all-true?'
false
eu -e '[true, true, false] any-true?'
true
all and any
Test with a predicate:
eu -e '[2, 4, 6] all(> 0)'
true
eu -e '[1, 2, 3] any(zero?)'
false
Reordering
reverse
eu -e '[:a, :b, :c] reverse'
- c
- b
- a
zip-with
Combine two lists element by element:
eu -e 'zip-with(+, [1, 2, 3], [10, 20, 30])'
- 11
- 22
- 33
zip-with and pair to create blocks
eu -e 'zip-with(pair, [:x, :y, :z], [1, 2, 3]) block'
x: 1
y: 2
z: 3
Infinite Lists
Eucalypt supports lazy evaluation, so you can work with infinite lists:
eu -e 'repeat(:x) take(4)'
- x
- x
- x
- x
Use take to extract a finite portion.
Sorting
qsort
Sort with a comparison function:
eu -e '[5, 3, 1, 4, 2] qsort(<)'
- 1
- 2
- 3
- 4
- 5
sort-nums
A convenience for sorting numbers in ascending order:
eu -e '[30, 10, 20] sort-nums'
- 10
- 20
- 30
Putting It Together
Here is a more complete example combining multiple list operations:
data: [
{ name: "Alice" score: 85 }
{ name: "Bob" score: 92 }
{ name: "Charlie" score: 78 }
{ name: "Diana" score: 95 }
]
top-scorers: data
filter(.score >= 90)
map(.name)
data:
- name: Alice
score: 85
- name: Bob
score: 92
- name: Charlie
score: 78
- name: Diana
score: 95
top-scorers:
- Bob
- Diana
Key Concepts
- Lists are created with
[...]and can be heterogeneous map,filter, andfoldl/foldrare the core transformation functionstake,drop,reverse,append(++), andconcatreshape listsall,any,all-true?, andany-true?test list conditions- Lazy evaluation allows working with infinite lists via
repeat qsortsorts with a custom comparator;sort-numssorts numbers