5.1.29. Functional Programming
This tutorial covers daslib/functional — lazy iterator adapters
and higher-order combinators for daslang.
Unlike daslib/linq which uses blocks and focuses on query syntax,
functional accepts lambdas and functions, emphasising composability.
5.1.29.1. filter and map
filter keeps elements matching a predicate.
map transforms each element:
var src <- [iterator for (x in range(8)); x]
var evens <- filter(src, @(x : int) : bool { return x % 2 == 0; })
var nums <- [iterator for (x in range(5)); x]
var squared <- map(nums, @(x : int) : int { return x * x; })
Both return lazy iterators — elements are produced on demand.
They accept lambdas (@) or named functions (@@is_even).
Note
filter, map, scan, and tap return generators and
only accept lambdas or functions — not blocks — because blocks
cannot be captured into generators.
5.1.29.2. reduce and fold
reduce combines elements pairwise. fold adds an initial seed:
var total = reduce(src) $(a, b : int) : int { return a + b }
var product = fold(src, 1) $(acc, x : int) : int { return acc * x }
reduce_or_default returns a fallback on empty input instead of panicking:
var safe = reduce_or_default(src, @(a, b : int) : int { return a + b; }, -1)
5.1.29.3. scan — running fold
scan yields every intermediate accumulator value:
var running <- scan(src, 0, @(acc, x : int) : int { return acc + x; })
// seed=0, then 0+1=1, 1+3=4, ...
5.1.29.4. Iterator combinators
chain(a, b)— concatenate two iteratorsenumerate(src)—(index, element)tuplespairwise(src)— consecutive pairs:(a,b), (b,c), ...islice(src, start, stop)— slice[start, stop)flatten(src)— flatten nested iterators one level
var en <- enumerate(names)
for (v in en) { print("{v._0}: {v._1}") }
var ca <- chain(first_half, second_half)
5.1.29.5. Generators
iterate(seed, fn)—seed, f(seed), f(f(seed)), ...infinitelyrepeat(val, n)— repeatvalntimes (or forever ifn< 0)cycle(src)— endlessly repeat an iterator
var powers <- iterate(1, @(x : int) : int { return x * 2; })
// 1, 2, 4, 8, 16, ...
var rep <- repeat(42, 3) // 42, 42, 42
5.1.29.6. Aggregation
sum(src)— sum all elementsany(src)— true if any element is truthyall(src)— true if all elements are truthy
5.1.29.7. Search and split
find(src, fn, default)— first match or default valuefind_index(src, fn)— index of first match, or-1partition(src, fn)— split into(matching, non_matching)arrays
var first_even = find(src, @@is_even, -1)
var parts = partition(src, @@is_even) // parts._0 = evens, parts._1 = odds
5.1.29.8. Side-effects and debugging
for_each(src, fn/block)— apply side-effect to every elementtap(src, fn)— passthrough with side-effect (debug tool)echo(x)— printxand return it unchanged
for_each(src) $(x : int) { total += x }
var tapped <- tap(src, @(x : int) { print("debug: {x}\n"); })
5.1.29.9. Composition
Chain these together to build data pipelines:
var big <- filter(src, @(x : int) : bool { return x >= 5; })
var doubled <- map(big, @(x : int) : int { return x * 2; })
var result = fold(doubled, 0) $(acc, x : int) : int { return acc + x }
See also
Full source: tutorials/language/29_functional.das
Next tutorial: JSON
LINQ tutorial for block-based query syntax.
Iterators and generators in the language reference.
Lambdas in the language reference.