Lists & Tuples
Nostos provides immutable Lists and fixed-size Tuples as fundamental data structures. They are often used together with pattern matching to process structured data.
Lists
Lists are immutable, singly linked-list based collections, similar to those found in functional programming languages. They are best suited for recursive processing and scenarios where prepending elements is efficient.
# Using list pattern matching (head | tail)
get_head([h | _]) = h
get_tail([_ | t]) = t
# Recursive function to sum list elements
sum_list([]) = 0
sum_list([x | xs]) = x + sum_list(xs)
main() = {
empty_list = []
numbers = [1, 2, 3, 4, 5]
head_val = get_head(numbers) # head_val is 1
tail_list = get_tail(numbers) # tail_list is [2, 3, 4, 5]
total_sum = sum_list(numbers) # total_sum is 15
# Prepending an element (creates a new list)
new_list = [0 | numbers] # new_list is [0, 1, 2, 3, 4, 5]
println(head_val)
println(total_sum)
}
Tuples
Tuples are fixed-size, ordered collections that can hold values of different types. They are commonly used for grouping related data or for functions that need to return multiple values.
# Destructuring tuples with pattern matching
get_x((x, _)) = x
get_name((name, _, _)) = name
# Function returning multiple values
divide_with_remainder(a, b) = (a / b, a % b)
main() = {
point_2d = (10, 20)
user_info = ("Alice", 30, true)
x_coord = get_x(point_2d) # x_coord is 10
name = get_name(user_info) # name is "Alice"
(quotient, remainder) = divide_with_remainder(10, 3)
println("10 / 3 = " ++ show(quotient) ++ " with remainder " ++ show(remainder))
}
Tuple Field Access
Access tuple elements by index using .0, .1, etc. or bracket notation.
main() = {
point = (10, 20, 30)
# Access by index using dot notation
x = point.0 # 10
y = point.1 # 20
z = point.2 # 30
# Or using bracket notation
first = point[0] # 10
# Get tuple length
len = point.length() # 3
println(show(x)) # 10
println(show(len)) # 3
}
Method Chaining
Nostos supports method call syntax that allows chaining operations fluently.
When you call x.f(y), it's equivalent to f(x, y).
This enables powerful, readable data transformations.
main() = {
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Chain operations fluently
result = numbers
.filter(x => x % 2 == 0) # Keep even numbers [2,4,6,8,10]
.map(x => x * x) # Square them [4,16,36,64,100]
.fold(0, (acc, x) => acc + x) # Sum them: 220
# Each step returns a new list, enabling the chain
evens = numbers.filter(x => x % 2 == 0) # [2, 4, 6, 8, 10]
doubled = evens.map(x => x * 2) # [4, 8, 12, 16, 20]
# Works with any function that takes the value as first argument
words = ["hello", "world"]
lengths = words.map(s => String.length(s)) # [5, 5]
# Sorting and transforming
sorted_desc = numbers.sort().reverse() # [10, 9, 8, ..., 1]
}
Common List Methods
.map(fn)
- Transform each element
.filter(pred)
- Keep matching elements
.fold(init, fn)
- Reduce to single value
.find(pred)
- Find first match
.sort()
- Sort elements
.reverse()
- Reverse order
.take(n)
- First n elements
.drop(n)
- Skip first n
.any(pred)
- True if any match
.all(pred)
- True if all match
.each(fn)
- Execute for side effects
.unique()
- Remove duplicates