aboutsummaryrefslogtreecommitdiff
path: root/docs/reductions.md
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-10-08 23:39:37 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-10-08 23:39:37 -0400
commit7e7ac77021f407d0c277d54ce4ad55ecf3942039 (patch)
treedc55e1e434b5bc242fe88d66f73641b2d12ba15c /docs/reductions.md
parentd741763293c9eeafdfe618acfc90e4352e3c2528 (diff)
Document reductions
Diffstat (limited to 'docs/reductions.md')
-rw-r--r--docs/reductions.md112
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()
+```