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 a parenthesized infix operator followed by a colon, followed by a collection:
nums := [10, 20, 30]
sum := (+: nums)
assert sum == 60
Reductions return an optional value which will be a null value if the thing
being iterated over has no values. In such cases, the reduction is undefined.
As with all optionals, you can use either the postfix ! operator to perform
a runtime check and error if there's a null value, or you can use or to
provide a fallback value:
nums : [Int] = []
sum := (+: nums)
assert sum == none
assert sum or 0 == 0
nums = [10, 20]
assert (+: nums)! == 30
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:
# Sum:
assert (+: [10, 20, 30])! == 60
# Product:
assert (*: [2, 3, 4])! == 24
# Any:
assert (or: [no, yes, no])! == yes
# All:
assert (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.
# Get the maximum value:
assert (_max_: [10, 30, 20])! == 30
# Get the minimum value:
assert (_min_: [10, 30, 20])! == 10
Reducers 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.
# Get the longest text:
assert (_max_.length: ["z", "aaaaa", "mmm"])! == "aaaaa"
# Get the number with the biggest absolute value:
assert (_max_.abs(): [1, -2, 3, -4])! == -4
You can also use suffixes on other operators:
texts := ["x", "y", "z"]
assert (==: texts) == no
assert (==.length: texts) == yes
assert (+.length: texts) == 3
nums := [1, 2, -3]
assert (+.abs(): nums) == 6
Comprehensions
Reductions work not only with iterable values (lists, sets, integers, etc.), but also with comprehensions. You can use comprehensions to perform reductions while filtering out values or while applying a transformation:
# Sum the lengths of these texts:
assert (+: t.length for t in ["a", "bc", "def"])! == 6
# Sum the primes between 1-100:
assert (+: i for i in 100 if i.is_prime())! == 1060
1 # Reductions3 In Tomo, reductions are a way to express the idea of folding or reducing a4 collection of values down to a single value. Reductions use a parenthesized5 infix operator followed by a colon, followed by a collection:8 nums := [10, 20, 30]9 sum := (+: nums)10 assert sum == 6011 ```13 Reductions return an optional value which will be a null value if the thing14 being iterated over has no values. In such cases, the reduction is undefined.17 provide a fallback value:20 nums : [Int] = []21 sum := (+: nums)23 assert sum == none25 assert sum or 0 == 027 nums = [10, 20]28 assert (+: nums)! == 3029 ```36 # Sum:37 assert (+: [10, 20, 30])! == 6039 # Product:40 assert (*: [2, 3, 4])! == 2442 # Any:43 assert (or: [no, yes, no])! == yes45 # All:46 assert (and: [no, yes, no])! == no47 ```49 ## Minimum and Maximum55 # Get the maximum value:56 assert (_max_: [10, 30, 20])! == 3058 # Get the minimum value:59 assert (_min_: [10, 30, 20])! == 1060 ```62 Reducers also support field and method call suffixes, which makes it very easy63 to compute the argmin/argmax (or keyed minimum/maximum) of a collection. This68 # Get the longest text:69 assert (_max_.length: ["z", "aaaaa", "mmm"])! == "aaaaa"71 # Get the number with the biggest absolute value:72 assert (_max_.abs(): [1, -2, 3, -4])! == -473 ```75 You can also use suffixes on other operators:78 texts := ["x", "y", "z"]79 assert (==: texts) == no80 assert (==.length: texts) == yes81 assert (+.length: texts) == 383 nums := [1, 2, -3]84 assert (+.abs(): nums) == 685 ```87 ## Comprehensions89 Reductions work not only with iterable values (lists, sets, integers, etc.),90 but also with comprehensions. You can use comprehensions to perform reductions91 while filtering out values or while applying a transformation:94 # Sum the lengths of these texts:95 assert (+: t.length for t in ["a", "bc", "def"])! == 697 # Sum the primes between 1-100:98 assert (+: i for i in 100 if i.is_prime())! == 106099 ```