@@ -36,31 +36,80 @@ mul_prod(x::Real, y::Real)::Real = x * y
3636
3737# # foldl && mapfoldl
3838
39- function  mapfoldl_impl (f, op, nt:: NamedTuple{(:init,)} , itr, i... )
40-     init =  nt. init
39+ mapfoldl_impl (f, op, nt, itr) =  foldl_impl (op, nt, Generator (f, itr))
40+ 
41+ function  foldl_impl (op, nt, itr)
42+     op′, itr′ =  _xfadjoint (BottomRF (op), itr)
43+     return  _foldl_impl (op′, nt, itr′)
44+ end 
45+ 
46+ function  _foldl_impl (op, nt, itr)
47+     init =  get (nt, :init , _InitialValue ())
4148    #  Unroll the while loop once; if init is known, the call to op may
4249    #  be evaluated at compile time
43-     y =  iterate (itr, i ... )
50+     y =  iterate (itr)
4451    y ===  nothing  &&  return  init
45-     v =  op (init, f ( y[1 ]) )
52+     v =  op (init, y[1 ])
4653    while  true 
4754        y =  iterate (itr, y[2 ])
4855        y ===  nothing  &&  break 
49-         v =  op (v, f ( y[1 ]) )
56+         v =  op (v, y[1 ])
5057    end 
58+     v isa  _InitialValue &&  reduce_empty_iter (op, itr, IteratorEltype (itr))
5159    return  v
5260end 
5361
54- function  mapfoldl_impl (f, op, nt:: NamedTuple{()} , itr)
55-     y =  iterate (itr)
56-     if  y ===  nothing 
57-         return  Base. mapreduce_empty_iter (f, op, itr, IteratorEltype (itr))
58-     end 
59-     x, i =  y
60-     init =  mapreduce_first (f, op, x)
61-     return  mapfoldl_impl (f, op, (init= init,), itr, i)
62+ struct  _InitialValue end 
63+ 
64+ struct  BottomRF{T}
65+     rf:: T 
6266end 
6367
68+ @inline  (op:: BottomRF )(:: _InitialValue , x) =  x
69+ @inline  (op:: BottomRF )(acc, x) =  op. rf (acc, x)
70+ 
71+ struct  MappingRF{F, T}
72+     f:: F 
73+     rf:: T 
74+ end 
75+ 
76+ @inline  (op:: MappingRF )(acc, x) =  op. rf (acc, op. f (x))
77+ 
78+ struct  FilteringRF{F, T}
79+     f:: F 
80+     rf:: T 
81+ end 
82+ 
83+ @inline  (op:: FilteringRF )(acc, x) =  op. f (x) ?  op. rf (acc, x) :  acc
84+ 
85+ """ 
86+     _xfadjoint(op, itr) -> op′, itr′ 
87+ 
88+ Given a pair of reducing function `op` and an iterator `itr`, return a pair 
89+ `(op′, itr′)` of similar types.  If the iterator `itr` is transformed by an 
90+ iterator transform `ixf` whose adjoint transducer `xf` is known, `op′ = xf(op)` 
91+ and `itr′ = "parent" of itr` is returned.  Otherwise, `op` and `itr` are 
92+ returned as-is.  For example, transducer `rf -> MappingRF(f, rf)` is the 
93+ adjoint of iterator transform `itr -> Generator(f, itr)`. 
94+ 
95+ Nested iterator transforms are converted recursively.  That is to say, 
96+ given `op` and 
97+ 
98+     itr = (ixf₁ ∘ ixf₂ ∘ ... ∘ ixfₙ)(itr′) 
99+ 
100+ what is returned is `itr′` and 
101+ 
102+     op′ = (xfₙ ∘ ... ∘ xf₂ ∘ xf₁)(op) 
103+ """ 
104+ _xfadjoint (op, itr) =  (op, itr)
105+ _xfadjoint (op, itr:: Generator ) = 
106+     if  itr. f ===  identity
107+         op, itr. iter
108+     else 
109+         _xfadjoint (MappingRF (itr. f, op), itr. iter)
110+     end 
111+ _xfadjoint (op, itr:: Filter ) = 
112+     _xfadjoint (FilteringRF (itr. flt, op), itr. itr)
64113
65114""" 
66115    mapfoldl(f, op, itr; [init]) 
@@ -92,21 +141,14 @@ foldl(op, itr; kw...) = mapfoldl(identity, op, itr; kw...)
92141# # foldr & mapfoldr
93142
94143mapfoldr_impl (f, op, nt:: NamedTuple{(:init,)} , itr) = 
95-     mapfoldl_impl (f, (x,y) ->  op (y,x), nt, Iterators. reverse (itr))
96- 
97- #  we can't just call mapfoldl_impl with (x,y) -> op(y,x), because
98- #  we need to use the type of op for mapreduce_empty_iter and mapreduce_first.
99- function  mapfoldr_impl (f, op, nt:: NamedTuple{()} , itr)
100-     ritr =  Iterators. reverse (itr)
101-     y =  iterate (ritr)
102-     if  y ===  nothing 
103-         return  Base. mapreduce_empty_iter (f, op, itr, IteratorEltype (itr))
104-     end 
105-     x, i =  y
106-     init =  mapreduce_first (f, op, x)
107-     return  mapfoldl_impl (f, (x,y) ->  op (y,x), (init= init,), ritr, i)
144+     mapfoldl_impl (f, FlipArgs (op), nt, Iterators. reverse (itr))
145+ 
146+ struct  FlipArgs{F}
147+     f:: F 
108148end 
109149
150+ @inline  (f:: FlipArgs )(x, y) =  f. f (y, x)
151+ 
110152""" 
111153    mapfoldr(f, op, itr; [init]) 
112154
@@ -234,6 +276,11 @@ reduce_empty(::typeof(mul_prod), T) = reduce_empty(*, T)
234276reduce_empty (:: typeof (mul_prod), :: Type{T} ) where  {T<: SmallSigned }  =  one (Int)
235277reduce_empty (:: typeof (mul_prod), :: Type{T} ) where  {T<: SmallUnsigned } =  one (UInt)
236278
279+ reduce_empty (op:: BottomRF , T) =  reduce_empty (op. rf, T)
280+ reduce_empty (op:: MappingRF , T) =  mapreduce_empty (op. f, op. rf, T)
281+ reduce_empty (op:: FilteringRF , T) =  reduce_empty (op. rf, T)
282+ reduce_empty (op:: FlipArgs , T) =  reduce_empty (op. f, T)
283+ 
237284""" 
238285    Base.mapreduce_empty(f, op, T) 
239286
@@ -251,10 +298,12 @@ mapreduce_empty(::typeof(abs2), op, T)     = abs2(reduce_empty(op, T))
251298mapreduce_empty (f:: typeof (abs),  :: typeof (max), T) =  abs (zero (T))
252299mapreduce_empty (f:: typeof (abs2), :: typeof (max), T) =  abs2 (zero (T))
253300
254- mapreduce_empty_iter (f, op, itr, :: HasEltype ) =  mapreduce_empty (f, op, eltype (itr))
255- mapreduce_empty_iter (f, op:: typeof (& ), itr, :: EltypeUnknown ) =  true 
256- mapreduce_empty_iter (f, op:: typeof (| ), itr, :: EltypeUnknown ) =  false 
257- mapreduce_empty_iter (f, op, itr, :: EltypeUnknown ) =  _empty_reduce_error ()
301+ #  For backward compatibility:
302+ mapreduce_empty_iter (f, op, itr, ItrEltype) = 
303+     reduce_empty_iter (MappingRF (f, op), itr, ItrEltype)
304+ 
305+ reduce_empty_iter (op, itr, :: HasEltype ) =  reduce_empty (op, eltype (itr))
306+ reduce_empty_iter (op, itr, :: EltypeUnknown ) =  _empty_reduce_error ()
258307
259308#  handling of single-element iterators
260309""" 
0 commit comments