Document reductions
This commit is contained in:
parent
d741763293
commit
7e7ac77021
112
docs/reductions.md
Normal file
112
docs/reductions.md
Normal file
@ -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()
|
||||
```
|
Loading…
Reference in New Issue
Block a user