/
empty_result_handling.jl
87 lines (63 loc) · 2.41 KB
/
empty_result_handling.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# # Empty result handling
#
# Transducible processes such as [`foldl`](@ref) try to
# do the right thing even when `init` is not given, _if_ the given
# binary operation `step` is supported by
# [InitialValues.jl](https://juliafolds.github.io/InitialValues.jl/dev/)
# (for example, `+`, `*`, `&`, and `|` are supported). However, those
# functions _throw_ an exception if the given collection is empty or
# filtered out by the transducers:
using LiterateTest #src
using Test #src
using Transducers
add1(x) = x + 1
@evaltest_throw "foldl(*, Map(add1), [])" begin
@test ans isa Transducers.EmptyResultError
end
# To write robust code, it is recommended to use `init` if there is a
# reasonable default. However, it may be useful to postpone
# "materializing" the result. In such case, `Init` can be used as a
# placeholder.
result = foldl(*, Map(add1), [], init=Init)
nothing # hide
# `init=Init` is a short-hand notation of `init=Init(*)` (so that `*` does
# not have to be repeated):
@assert result === foldl(*, Map(add1), [], init=Init(*))
# Note also that [`transduce`](@ref) can be used for passing `init` as
# a positional argument:
@assert result === transduce(Map(add1), Completing(*), Init, [])
# Since the input collection `[]` is empty, `result` is `Init(*)` (which
# is an `InitialValues.InitialValue`):
using InitialValues: InitialValue
@assert result::InitialValue === Init(*)
# `Init(*)` is the left identity of `*`. Multiplying it with any `x`
# from right returns `x` as-is. This property may be useful, e.g., if
# `result` is known to be a scalar that is multiplied by a matrix just
# after the `foldl`:
@test begin
result * ones(2, 2)
end == ones(2, 2)
# The identities `Init(*)` and `Init(+)` can be `convert`ed to numbers:
@test begin
convert(Int, Init(*))
end === 1
# `Init(*)` can also be `convert`ed to a `String`:
@test begin
convert(String, Init(*))
end === ""
# This means that no special code is required if the result is going
# to be stored into, e.g., an `Array` or a `struct`:
@test begin
xs = [true, true]
xs[1] = Init(+)
xs
end == [false, true]
# They can be converted into numbers also by using `Integer`:
@test begin
Integer(Init(+))
end === 0
# or `float`:
@test begin
float(Init(*))
end === 1.0
#-