1 /// This module defines the core transducer primitives. 2 module rxd.xf.xform; 3 4 import std.meta, std.traits; 5 import std.range : ElementType; 6 7 import rxd.meta2.lambda : λ; 8 import rxd.meta2.switch_n : switch2, switch3; 9 10 auto outputRf = λ!((output, input) 11 { 12 import std.range : put; 13 output.put(input); 14 return output; 15 }); 16 17 auto transform(alias fn, I, O)(I input, O output) 18 { 19 return input.accumulate(map!fn()(outputRf), output); 20 } 21 22 private T[n] s(T, size_t n)(T[n] literal) { return literal; } 23 24 /// Showcase transform (map + copy) 25 nothrow @safe @nogc 26 unittest 27 { 28 auto arr1 = [4, 2, 7, 4, 6, 5, 1].s; 29 auto arr2 = typeof(arr1).init; 30 31 transform!(x => x * 2)(arr1[], arr2[]); 32 33 assert (arr2 == [8, 4, 14, 8, 12, 10, 2]); 34 } 35 36 /// Showcase type sequence transformation 37 pure nothrow @safe @nogc 38 unittest 39 { 40 import rxd.meta2.type; 41 import std.meta : AliasSeq; 42 43 auto trf = λ!( (state, input) => state.append(input) ); 44 45 alias transform = (input, xform) => 46 accumulate(input, xform(trf), aliasTuple()); 47 48 auto tuple = AliasTuple!(Type!int, Type!double, Type!char)(); 49 50 auto large = filter!(t => t.typeOf.sizeof >= 4); 51 auto result1 = transform(tuple, large); 52 static assert (is(result1.typeSeq == AliasSeq!(int, double))); 53 54 auto toArray = map!(t => t[]); 55 auto result2 = transform(tuple, toArray); 56 static assert (is(result2.typeSeq == AliasSeq!(int[], double[], char[]))); 57 58 auto xf = large(toArray(trf)); 59 auto result3 = tuple.accumulate(xf, aliasTuple()); 60 static assert (is(result3.typeSeq == AliasSeq!(int[], double[]))); 61 } 62 63 /// Showcase reduce-like usage 64 pure nothrow @safe @nogc 65 unittest 66 { 67 import std.range : iota, chain; 68 69 assert (1.iota(4).accumulate(λ!((a, b) => a + b), 0) == 6); 70 71 assert (1.iota(5).accumulate(λ!((a, b) => a * b), 1) == 24); 72 73 //assert (["I", "am", "one"].s[].accumulate(λ!((a, b) => chain(a, b, " ")), "") == "I am one "); 74 } 75 76 /// Showcase composition 77 unittest 78 { 79 import std.stdio, std.range; 80 auto sum = λ!((a, b) => a + b); 81 82 auto odd = filter!(x => x % 2 == 1); 83 assert (1.iota(4).accumulate(odd(sum), 0) == 1 + 3); 84 85 auto mulBy2 = map!(x => x * 2); 86 assert (1.iota(4).accumulate(mulBy2(sum), 0) == 2 + 4 + 6); 87 88 assert (1.iota(4).accumulate(odd(mulBy2(sum)), 0) == 2 + 6); 89 } 90 91 /// 92 unittest 93 { 94 //auto rangeWrapperRf = λ!((state, input) 95 //{ 96 // import std.range : put; 97 // output.put(input); 98 // return output; 99 //}); 100 101 //alias sequence = (input, xform) => 102 // input.accumulate(xform(outputRf), output); 103 104 //writeln(transform([1, 2, 3], map2((int x) => x + 1))); 105 } 106 107 /// 108 auto map(alias mapFn)() 109 { 110 return λ!((step) { 111 return λ!((result, input) { 112 return step(result, mapFn(input)); 113 }); 114 }); 115 } 116 117 /// 118 auto filter(alias filterPred)() 119 { 120 return λ!( 121 (step) 122 { 123 return λ!( 124 (rf, result, input) 125 { 126 import rxd.meta2.type : isType, isAliasTuple; 127 static if (isType!(typeof(input)) || 128 isAliasTuple!(typeof(input))) 129 { 130 static if (filterPred(typeof(input).init)) 131 return rf(result, input); 132 else 133 return result; 134 } 135 else 136 { 137 return filterPred(input)? 138 rf(result, input) : 139 result; 140 } 141 142 //mixin (switch2!( 143 // "filterPred(input)", 144 // "return rf(result, input);", 145 // "return result;", 146 //)); 147 } 148 )(step); 149 } 150 ); 151 }; 152 153 /// 154 auto accumulate(Rf, S, In, size_t line = __LINE__)(In input, Rf step, S state) 155 if ( is(ElementType!In E)) 156 { 157 pragma (msg, line.stringof ~ " accumulate: S(", typeof(S.init), 158 "), E(", typeof(ElementType!In.init), ") "); 159 160 static if (__traits(compiles, { enum b = input.empty; } )) 161 { 162 static if (input.empty) 163 return state; 164 else 165 return step(accumulate(input.dropBackOne, step, state), input.back); 166 } 167 else 168 { 169 foreach (elem; input) 170 state = step(state, elem); 171 172 return state; 173 } 174 // mixin (switch3!("input.empty", 175 // "return state;", 176 // "return step(accumulate(input.dropBackOne, step, state), input.back);", 177 // q{ 178 // foreach (elem; input) 179 // state = step(state, elem); 180 // 181 // return state; 182 // } 183 // )); 184 } 185 186 /// 187 188 189 190 struct Transducer(Input, Output = Input) 191 { 192 193 } 194 195 unittest 196 { 197 //Transducer!int filter_odd = filter((int x) => x % 2); 198 199 //Transducer!(int, string) serialize = map((int x) => "int" ); 200 }