Collections
Nanyx provides powerful collection types for working with sequences of data. The primary collection type is the list, which is immutable and efficiently supports functional operations.
Lists
Lists are immutable sequences of values:
-- List creation
def numbers = [1, 2, 3, 4, 5]
def names = ["Alice", "Bob", "Charlie"]
def empty = []List Type
Lists have a generic type list(a):
def numbers: list(int) = [1, 2, 3]
def names: list(string) = ["Alice", "Bob"]List Operations
Map
Transform each element:
def doubled = [1, 2, 3] \map { * 2 }
-- Result: [2, 4, 6]
def names = users \map { .name }Filter
Keep elements that match a predicate:
def evens = [1, 2, 3, 4, 5] \filter { n -> n % 2 == 0 }
-- Result: [2, 4]
def adults = users \filter { .age >= 18 }Fold
Reduce a list to a single value:
def sum = [1, 2, 3, 4] \fold(0) { + }
-- Result: 10
def product = [1, 2, 3, 4] \fold(1) { * }
-- Result: 24List Destructuring
Pattern match on lists:
-- Head and tail
rec sumList: list(int) -> int = {
| [] -> 0
| [head, ...tail] -> head + sumList(tail)
}
-- Multiple elements
def process = {
| [] -> "empty"
| [x] -> "one element"
| [x, y] -> "two elements"
| [x, y, ...rest] -> "many elements"
}List Construction
Build lists with spread syntax:
-- Prepend elements
def newList = [1, 2, ...oldList]
-- Append (less efficient)
def extended = [...list1, ...list2]
-- In pattern matching
rec map: (list(a), (a -> b)) -> list(b) = {
| [], _ -> []
| [head, ...tail], f -> [f(head), ...map(tail, f)]
}Common List Functions
Length
rec length: list(a) -> int = {
| [] -> 0
| [_, ...tail] -> 1 + length(tail)
}Reverse
def reverse: list(a) -> list(a) = { xs ->
xs \fold([]) { acc, x -> [x, ...acc] }
}Take
rec take: (list(a), int) -> list(a) = {
| [], _
| _, { <= 0 } -> []
| [head, ...tail], n -> [head, ...take(tail, n - 1)]
}Drop
rec drop: (list(a), int) -> list(a) = {
| [], _
| xs, { <= 0 } -> xs
| [_, ...tail], n -> drop(tail, n - 1)
}Ranges
Create numeric sequences:
def oneToTen = [1..10]
-- Result: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def evens = [2, ...4..20]
-- Result: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]List Comprehensions
Build lists declaratively:
-- Simple comprehension
def squares = [for 1..10 | x -> x * x ]
-- With filter
def evenSquares = [for 1..10 | x if x % 2 == 0 -> yield! x * x
| _ -> ()]
-- Zipped generators
def pairs = [for (1..3), (1..3) | x, y -> (x, y)]Other Collection Types
Maps
Key-value collections:
def ages = dict {
"Alice" => 30
"Bob" => 25
"Charlie" => 35
}
def aliceAge = ages["Alice"] -- #some(30)
def unknownAge = ages["Unknown"] -- #noneSets
Unique value collections:
def numbers = set [1, 2, 3, 2, 1]
-- Result: set [1, 2, 3]
def union = set1 \union set2
def intersection = set1 \intersect set2Sequences and Lazy Evaluation
For large or infinite collections, use sequences:
-- Infinite sequence
def naturals = Seq.unfold(0) { + 1 }
-- Take first 10
def firstTen = naturals \take(10) \toListPractical Examples
Finding Elements
rec find: (list(a), (a -> bool)) -> Option(a) = {
| [] -> #none
| [head, ...] if predicate(head) ->
| [_, ...tail] -> find(tail, predicate)
}
def firstEven = [1, 3, 4, 5] \find { % 2 == 0 }
-- Result: #some(4)Grouping
def groupBy: (list(a), (a -> b)) -> Map(b, list(a)) = { xs, keyFn ->
xs \fold(dict {}) { acc, x ->
def key = keyFn(x)
def existing = acc[key] \getOrElse([])
acc \insert(key, [x, ...existing])
}
}
def byAge = users \groupBy { .age }Sorting
def sort: list(a) -> list(a) = {
| [] -> []
| [pivot, ...rest] ->
def smaller = rest \filter { <= pivot }
def larger = rest \filter { > pivot }
[...sort(smaller), pivot, ...sort(larger)]
}