diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-10-08 23:39:37 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-10-08 23:39:37 -0400 |
| commit | 7e7ac77021f407d0c277d54ce4ad55ecf3942039 (patch) | |
| tree | dc55e1e434b5bc242fe88d66f73641b2d12ba15c /docs | |
| parent | d741763293c9eeafdfe618acfc90e4352e3c2528 (diff) | |
Document reductions
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/reductions.md | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/docs/reductions.md b/docs/reductions.md new file mode 100644 index 00000000..143a59ad --- /dev/null +++ b/docs/reductions.md @@ -0,0 +1,112 @@ +# Reductions + +In Tomo, reductions are a way to express the idea of folding or reducing a +collection of values down to a single value. Reductions use an infix operator +surrounded by parentheses, followed by a collection: + +```tomo +nums := [10, 20, 30] +sum := (+) nums +>> sum += 60 +``` + +Reductions can be used as an alternative to generic functions like `sum()`, +`product()`, `any()`, and `all()` in Python, or higher-order functions like +`foldl` and `foldr` in functional programming: + +```tomo +# Sum: +>> (+) [10, 20, 30] += 60 + +# Product: +>> (*) [2, 3, 4] += 24 + +# Any: +>> (or) [no, yes, no] += yes + +# All: +>> (and) [no, yes, no] += no +``` + +## Minimum and Maximum + +Reductions are _especially_ useful for finding the minimum or maximum values in +a collection using the `_min_` and `_max_` infix operators. + +```tomo +# Get the maximum value: +>> (_max_) [10, 30, 20] += 30 + +# Get the minimum value: +>> (_min_) [10, 30, 20] += 10 +``` + +The `_min_` and `_max_` operators also support field and method call suffixes, +which makes it very easy to compute the argmin/argmax (or keyed +minimum/maximum) of a collection. This is when you want to get the minimum or +maximum value _according to some feature_. + +```tomo +# Get the longest text: +>> (_max_.length) ["z", "aaaaa", "mmm"] += "aaaaa" + +# Get the number with the biggest absolute value: +>> (_max_:abs()) [1, -2, 3, -4] += -4 +``` + +## Comprehensions + +Reductions work not only with iterable values (arrays, sets, integers, etc.), +but also with comprehensions. You can use comprehensions to perform reductions +while filtering out values or while applying a transformation: + +```tomo +# Sum the lengths of these texts: +>> (+) t.length for t in ["a", "bc", "def"] += 6 + +# Sum the primes between 1-100: +>> (+) i for i in 100 if i:is_prime() += 1060 +``` + +## Empty Collection Behavior + +If a collection has no members, the default behavior for a reduction is to +create a runtime error and halt the program with an informative error message. +If you instead want to provide a default fallback value, you can use `else:` to +give one: + +```tomo +empty := [:Int] +>> (+) empty else: -1 += -1 + +>> (+) empty +# Error: empty iterable! +``` + +You can also provide your own call to `fail()` or `exit()` with a custom error +message, or a short-circuiting control flow statement (`return`, `stop`, +`skip`) like this: + +```tomo +>> (_max_) things else: exit("No things!") + +for nums in num_arrays: + product := (*) nums else: skip + do_thing(product) + +func remove_best(things:[Thing]): + best := (_max_.score) things else: return + best:remove() +``` |
