/
comprehensions.jl
173 lines (129 loc) · 4 KB
/
comprehensions.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
const Comprehension = Union{
Iterators.Generator,
Iterators.Filter,
Iterators.Flatten,
}
"""
eduction(iterator::Iterators.Generator)
eduction(iterator::Iterators.Filter)
eduction(iterator::Iterators.Flatten)
Convert an `iterator` to an eduction. The iterators that are
typically used in the generator comprehensions are supported.
!!! compat "Transducers.jl 0.3"
New in version 0.3.
# Examples
```jldoctest
julia> using Transducers
julia> iter = (y for x in 1:10 if x % 2 == 0 for y in (x, x + 1));
julia> ed = eduction(iter);
julia> collect(iter) == collect(ed)
true
```
"""
eduction(itr::Comprehension) = eduction(extract_transducer(itr)...)
eduction(ed::Eduction) = ed
"""
Transducer(iterator::Iterators.Generator)
Transducer(iterator::Iterators.Filter)
Transducer(iterator::Iterators.Flatten)
Extract "processing" part of an `iterator` as a `Transducer`. The
"data source" iterator (i.e., `xs` in `(f(x) for x in xs)`) is ignored
and `nothing` must be used as a place holder (i.e., `(f(x) for x in
nothing)`).
See also [`eduction`](@ref).
!!! compat "Transducers.jl 0.3"
New in version 0.3.
# Examples
```jldoctest
julia> using Transducers
julia> xf1 = Transducer(2x for x in nothing if x % 2 == 0);
julia> xf2 = opcompose(Filter(x -> x % 2 == 0), Map(x -> 2x)); # equivalent
julia> xs = 1:10
collect(xf1, xs) == collect(xf2, xs)
true
```
"""
function Transducer(iter::Comprehension)
xf, dataiter = extract_transducer(iter)
dataiter === nothing && return xf
if dataiter isa Iterators.ProductIterator
throw(ArgumentError("""
Conversion of the product generator comprehension, i.e.,
Transducer(... for x in xs, y in ys ...)
is not supported.
"""))
else
throw(ArgumentError("""
Unsupported iterator:
$(typeof(dataiter))
Note that the "data source" iterator must be set to `nothing`.
"""))
end
end
iterinner(iter::Iterators.Generator) = iter.iter
iterinner(iter::Iterators.Filter) = iter.itr
iterinner(iter::Iterators.Flatten) = iter.it
# iterf(iter::Iterators.Generate) = iter.f
# iterf(iter::Iterators.Filter) = iter.flt
"""
extract_transducer(foldable) -> (xf, foldable′)
"Reverse" of [`eduction`](@ref).
# Examples
```jldoctest
julia> using Transducers
julia> double(x) = 2x;
julia> xs = 1:10;
julia> xf, foldable = Transducers.extract_transducer(double(x) for x in xs);
julia> xf == Map(double)
true
julia> foldable == xs
true
```
"""
extract_transducer(iter) = IdentityTransducer(), iter
extract_transducer(ed::Eduction) = Transducer(ed.rf), ed.coll
function extract_transducer(iter::Iterators.Generator)
xf, bottom = extract_transducer(iterinner(iter))
return Map(iter.f) ∘ xf, bottom
end
function extract_transducer(iter::Iterators.Filter)
xf, bottom = extract_transducer(iterinner(iter))
return Filter(iter.flt) ∘ xf, bottom
end
function extract_transducer(iter::Iterators.Flatten)
xf, bottom = extract_transducer(iterinner(iter))
return Cat() ∘ xf, bottom
end
"""
Transducers.NoAdjoint(itr)
Bypass the optimization step by [`retransform`](@ref).
"""
struct NoAdjoint{T}
itr::T
end
SplittablesBase.amount(itr::NoAdjoint) = amount(itr.itr)
extract_transducer(itr::NoAdjoint) = IdentityTransducer(), itr.itr
"""
Transducers.retransform(rf, itr) -> rf′, itr′
Extract transformations in `rf` and `itr` and use the appropriate adjoint for
better performance.
# Examples
```jldoctest
julia> using Transducers
julia> double(x) = 2x;
julia> itr0 = 1:10;
julia> itr1 = (double(x) for x in itr0);
julia> rf, itr2 = Transducers.retransform(+, itr1);
julia> itr2 === itr0
true
julia> rf == reducingfunction(Map(double), +)
true
```
"""
function retransform(rf, itr1)
xf, itr0 = extract_transducer(itr1)
return reducingfunction(xf, rf), itr0
end
# TODO: Consider doing the "opposite" of `extract_transducer` for
# `Partition` etc.:
# https://github.com/JuliaFolds/Transducers.jl/issues/7