<div dir="ltr">The relevant forum post <a href="https://forum.lazarus.freepascal.org/index.php/topic,45818.msg324506.html#msg324506">can be found here.</a><div><br></div><div>Currently, this just implements "Map", "Filter" and "Reduce", but I thought I'd get some feedback / opinions on what the best area of the FPC codebase for the unit to go would be / e.t.c. on the whole thing before I went any further.</div><div><br></div><div>Two things to note:</div><div><br></div><div>A) My implementation takes advantage of the (undocumented) fact that you can indeed have generic type helpers if you define them inside the scope of another generic type. This allows for a significantly nicer API than would be otherwise possible (I.E. an end user doesn't even have to directly use generic themselves if they don't want to), and also for easy declaration of type aliases that then just automatically have the routines associated with them.</div><div><br></div><div>B) Oddly, this kind of use of type helpers only works in {$mode Delphi}, and in fact crashes the compiler in {$mode ObjFPC}. This is obviously a bug that I'll probably make a report for on the tracker at some point. That said, the unit I've written can of course be <b>used</b> from other units that use any other compiler mode at all without issues, which makes the bug not really directly a problem in this case.</div><div><pre style="color:rgb(0,0,0)"><code><font size="2" face="Courier New"><font color="black"><b>unit </b>Functional<font color="red">;
<b>{$mode Delphi}{$H+}
</b></font><b>interface
type
</b>TArrayHelper<font color="red"><</font>T<font color="red">> = </font><b>record
public type
</b>TMapModifier <font color="red">= </font><b>function</b><font color="red">(</font><b>constref </b>Current<font color="red">: </font>T<font color="red">): </font>T<font color="red">;
</font>TFilterTest <font color="red">= </font><b>function</b><font color="red">(</font><b>constref </b>Current<font color="red">: </font>T<font color="red">): </font>boolean<font color="red">;
</font>TReduceModifier <font color="red">= </font><b>procedure</b><font color="red">(</font><b>var </b>Accumulator<font color="red">: </font>T<font color="red">; </font><b>constref </b>Current<font color="red">: </font>T<font color="red">);
</font>ArrayType <font color="red">= </font><b>array of </b>T<font color="red">;
</font>THelperImpl <font color="red">= </font><b>record helper for </b>ArrayType
<b>function </b>Map<font color="red">(</font><b>const </b>Modifier<font color="red">: </font>TMapModifier<font color="red">): </font>ArrayType<font color="red">; </font><b>overload</b><font color="red">;
</font><b>function </b>Filter<font color="red">(</font><b>const </b>Test<font color="red">: </font>TFilterTest<font color="red">): </font>ArrayType<font color="red">; </font><b>overload</b><font color="red">;
</font><b>function </b>Reduce<font color="red">(</font><b>const </b>Modifier<font color="red">: </font>TReduceModifier<font color="red">): </font>T<font color="red">; </font><b>overload</b><font color="red">;
</font><b>class function </b>Map<font color="red">(</font><b>constref </b>Values<font color="red">: </font><b>array of </b>T<font color="red">; </font><b>const </b>Modifier<font color="red">: </font>TMapModifier<font color="red">): </font>ArrayType<font color="red">; </font>static<font color="red">; </font><b>overload</b><font color="red">;
</font><b>class function </b>Filter<font color="red">(</font><b>constref </b>Values<font color="red">: </font><b>array of </b>T<font color="red">; </font><b>const </b>Test<font color="red">: </font>TFilterTest<font color="red">): </font>ArrayType<font color="red">; </font>static<font color="red">; </font><b>overload</b><font color="red">;
</font><b>class function </b>Reduce<font color="red">(</font><b>constref </b>Values<font color="red">: </font><b>array of </b>T<font color="red">; </font><b>const </b>Modifier<font color="red">: </font>TReduceModifier<font color="red">): </font>T<font color="red">; </font>static<font color="red">; </font><b>overload</b><font color="red">;
</font><b>end</b><font color="red">;
</font><b>end</b><font color="red">;
</font><font color="blue"><b>(* These are defined without the usual T prefix to avoid any conflict
with possible existing type aliases. *)
</b></font>UInt8Array <font color="red">= </font>TArrayHelper<font color="red"><</font>Byte<font color="red">>.</font>ArrayType<font color="red">;
</font>ShortIntArray <font color="red">= </font>TArrayHelper<font color="red"><</font>ShortInt<font color="red">>.</font>ArrayType<font color="red">;
</font>SmallIntArray <font color="red">= </font>TArrayHelper<font color="red"><</font>SmallInt<font color="red">>.</font>ArrayType<font color="red">;
</font>UInt16Array <font color="red">= </font>TArrayHelper<font color="red"><</font>Word<font color="red">>.</font>ArrayType<font color="red">;
</font>UInt32Array <font color="red">= </font>TArrayHelper<font color="red"><</font>Cardinal<font color="red">>.</font>ArrayType<font color="red">;
</font>Int32Array <font color="red">= </font>TArrayHelper<font color="red"><</font>LongInt<font color="red">>.</font>ArrayType<font color="red">;
</font>Int64Array <font color="red">= </font>TArrayHelper<font color="red"><</font>Int64<font color="red">>.</font>ArrayType<font color="red">;
</font>UInt64Array <font color="red">= </font>TArrayHelper<font color="red"><</font>QWord<font color="red">>.</font>ArrayType<font color="red">;
</font>Float32Array <font color="red">= </font>TArrayHelper<font color="red"><</font>Single<font color="red">>.</font>ArrayType<font color="red">;
</font>Float64Array <font color="red">= </font>TArrayHelper<font color="red"><</font>Double<font color="red">>.</font>ArrayType<font color="red">;
</font>ShortStringArray <font color="red">= </font>TArrayHelper<font color="red"><</font><b>ShortString</b><font color="red">>.</font>ArrayType<font color="red">;
</font>AnsiStringArray <font color="red">= </font>TArrayHelper<font color="red"><</font><b>AnsiString</b><font color="red">>.</font>ArrayType<font color="red">;
</font>UnicodeStringArray <font color="red">= </font>TArrayHelper<font color="red"><</font><b>UnicodeString</b><font color="red">>.</font>ArrayType<font color="red">;
</font><b>implementation
function </b>TArrayHelper<font color="red"><</font>T<font color="red">>.</font>THelperImpl<font color="red">.</font>Map<font color="red">(</font><b>const </b>Modifier<font color="red">: </font>TMapModifier<font color="red">): </font>ArrayType<font color="red">;
</font><b>var </b>I<font color="red">: </font>PtrUInt<font color="red">;
</font><b>begin
</b>SetLength<font color="red">(</font>Result<font color="red">, </font>Length<font color="red">(</font>Self<font color="red">));
</font><b>for </b>I <font color="red">:= </font><font color="navy">0 </font><b>to </b>High<font color="red">(</font>Self<font color="red">) </font><b>do
</b>Result<font color="red">[</font>I<font color="red">] := </font>Modifier<font color="red">(</font>Self<font color="red">[</font>I<font color="red">]);
</font><b>end</b><font color="red">;
</font><b>function </b>TArrayHelper<font color="red"><</font>T<font color="red">>.</font>THelperImpl<font color="red">.</font>Filter<font color="red">(</font><b>const </b>Test<font color="red">: </font>TFilterTest<font color="red">): </font>ArrayType<font color="red">;
</font><b>var </b>I<font color="red">, </font>J<font color="red">: </font>PtrUInt<font color="red">;
</font><b>begin
</b>J <font color="red">:= </font><font color="navy">0</font><font color="red">;
</font>SetLength<font color="red">(</font>Result<font color="red">, </font>Length<font color="red">(</font>Self<font color="red">));
</font><b>for </b>I <font color="red">:= </font><font color="navy">0 </font><b>to </b>High<font color="red">(</font>Self<font color="red">) </font><b>do
if </b>Test<font color="red">(</font>Self<font color="red">[</font>I<font color="red">]) </font><b>then begin
</b>Result<font color="red">[</font>J<font color="red">] := </font>Self<font color="red">[</font>I<font color="red">];
</font>Inc<font color="red">(</font>J<font color="red">);
</font><b>end</b><font color="red">;
</font>SetLength<font color="red">(</font>Result<font color="red">, </font>J<font color="red">);
</font><b>end</b><font color="red">;
</font><b>function </b>TArrayHelper<font color="red"><</font>T<font color="red">>.</font>THelperImpl<font color="red">.</font>Reduce<font color="red">(</font><b>const </b>Modifier<font color="red">: </font>TReduceModifier<font color="red">): </font>T<font color="red">;
</font><b>var </b>I<font color="red">: </font>PtrUInt<font color="red">;
</font><b>begin
</b>Result <font color="red">:= </font>Self<font color="red">[</font><font color="navy">0</font><font color="red">];
</font><b>for </b>I <font color="red">:= </font><font color="navy">1 </font><b>to </b>High<font color="red">(</font>Self<font color="red">) </font><b>do
</b>Modifier<font color="red">(</font>Result<font color="red">, </font>Self<font color="red">[</font>I<font color="red">]);
</font><b>end</b><font color="red">;
</font><b>class function </b>TArrayHelper<font color="red"><</font>T<font color="red">>.</font>THelperImpl<font color="red">.</font>Map<font color="red">(</font><b>constref </b>Values<font color="red">: </font><b>array of </b>T<font color="red">; </font><b>const </b>Modifier<font color="red">: </font>TMapModifier<font color="red">): </font>ArrayType<font color="red">;
</font><b>var </b>I<font color="red">: </font>PtrUInt<font color="red">;
</font><b>begin
</b>SetLength<font color="red">(</font>Result<font color="red">, </font>Length<font color="red">(</font>Values<font color="red">));
</font><b>for </b>I <font color="red">:= </font><font color="navy">0 </font><b>to </b>High<font color="red">(</font>Values<font color="red">) </font><b>do
</b>Result<font color="red">[</font>I<font color="red">] := </font>Modifier<font color="red">(</font>Values<font color="red">[</font>I<font color="red">]);
</font><b>end</b><font color="red">;
</font><b>class function </b>TArrayHelper<font color="red"><</font>T<font color="red">>.</font>THelperImpl<font color="red">.</font>Filter<font color="red">(</font><b>constref </b>Values<font color="red">: </font><b>array of </b>T<font color="red">; </font><b>const </b>Test<font color="red">: </font>TFilterTest<font color="red">): </font>ArrayType<font color="red">;
</font><b>var </b>I<font color="red">, </font>J<font color="red">: </font>PtrUInt<font color="red">;
</font><b>begin
</b>J <font color="red">:= </font><font color="navy">0</font><font color="red">;
</font>SetLength<font color="red">(</font>Result<font color="red">, </font>Length<font color="red">(</font>Values<font color="red">));
</font><b>for </b>I <font color="red">:= </font><font color="navy">0 </font><b>to </b>High<font color="red">(</font>Values<font color="red">) </font><b>do
if </b>Test<font color="red">(</font>Values<font color="red">[</font>I<font color="red">]) </font><b>then begin
</b>Result<font color="red">[</font>J<font color="red">] := </font>Values<font color="red">[</font>I<font color="red">];
</font>Inc<font color="red">(</font>J<font color="red">);
</font><b>end</b><font color="red">;
</font>SetLength<font color="red">(</font>Result<font color="red">, </font>J<font color="red">);
</font><b>end</b><font color="red">;
</font><b>class function </b>TArrayHelper<font color="red"><</font>T<font color="red">>.</font>THelperImpl<font color="red">.</font>Reduce<font color="red">(</font><b>constref </b>Values<font color="red">: </font><b>array of </b>T<font color="red">; </font><b>const </b>Modifier<font color="red">: </font>TReduceModifier<font color="red">): </font>T<font color="red">;
</font><b>var </b>I<font color="red">: </font>PtrUInt<font color="red">;
</font><b>begin
</b>Result <font color="red">:= </font>Values<font color="red">[</font><font color="navy">0</font><font color="red">];
</font><b>for </b>I <font color="red">:= </font><font color="navy">1 </font><b>to </b>High<font color="red">(</font>Values<font color="red">) </font><b>do
</b>Modifier<font color="red">(</font>Result<font color="red">, </font>Values<font color="red">[</font>I<font color="red">]);
</font><b>end</b><font color="red">;
</font><b>end</b><font color="red">.
</font></font></font></code></pre>I also wrote a small example / test program to give an idea of how the unit can be used:</div><div><pre style="color:rgb(0,0,0)"><code><font size="2" face="Courier New"><font color="black"><b>program </b>TestFunctional<font color="red">;
<b>{$mode ObjFPC}{$H+}
</b></font><b>uses </b>Functional<font color="red">;
</font><b>function </b>NumMap<font color="red">(</font><b>constref </b>Current<font color="red">: </font>LongInt<font color="red">): </font>LongInt<font color="red">;
</font><b>begin
</b>Result <font color="red">:= </font>Current <font color="red">+ </font>Current<font color="red">;
</font><b>end</b><font color="red">;
</font><b>function </b>NumFilter<font color="red">(</font><b>constref </b>Current<font color="red">: </font>LongInt<font color="red">): </font>Boolean<font color="red">;
</font><b>begin
</b>Result <font color="red">:= </font>Current <font color="red">> </font><font color="navy">5</font><font color="red">;
</font><b>end</b><font color="red">;
</font><b>procedure </b>NumReduce<font color="red">(</font><b>var </b>Accumulator<font color="red">: </font>LongInt<font color="red">; </font><b>constref </b>Current<font color="red">: </font>LongInt<font color="red">);
</font><b>begin
</b>Accumulator <font color="red">+= </font>Current<font color="red">;
</font><b>end</b><font color="red">;
</font><b>function </b>StringMap<font color="red">(</font><b>constref </b>Current<font color="red">: </font><b>AnsiString</b><font color="red">): </font><b>AnsiString</b><font color="red">;
</font><b>begin
</b>Result <font color="red">:= </font>Current <font color="red">+ </font>Current<font color="red">;
</font><b>end</b><font color="red">;
</font><b>function </b>StringFilter<font color="red">(</font><b>constref </b>Current<font color="red">: </font><b>AnsiString</b><font color="red">): </font>boolean<font color="red">;
</font><b>begin
</b>Result <font color="red">:= </font>Current <font color="red">> </font><font color="blue">'e'</font><font color="red">;
</font><b>end</b><font color="red">;
</font><b>procedure </b>StringReduce<font color="red">(</font><b>var </b>Accumulator<font color="red">: </font><b>AnsiString</b><font color="red">; </font><b>constref </b>Current<font color="red">: </font><b>AnsiString</b><font color="red">);
</font><b>begin
</b>Accumulator <font color="red">+= </font>Current<font color="red">;
</font><b>end</b><font color="red">;
</font><b>var
</b>I<font color="red">: </font>LongInt<font color="red">;
</font>S<font color="red">: </font><b>AnsiString</b><font color="red">;
</font><b>begin
</b>WriteLn<font color="red">(</font><font color="blue">'Instanced Integer Map!'</font><font color="red">);
</font><b>for </b>I <b>in </b>Int32Array<font color="red">.</font>Create<font color="red">(</font><font color="navy">1</font><font color="red">, </font><font color="navy">2</font><font color="red">, </font><font color="navy">3</font><font color="red">, </font><font color="navy">4</font><font color="red">, </font><font color="navy">5</font><font color="red">, </font><font color="navy">6</font><font color="red">, </font><font color="navy">7</font><font color="red">, </font><font color="navy">8</font><font color="red">, </font><font color="navy">9</font><font color="red">, </font><font color="navy">10</font><font color="red">).</font>Map<font color="red">(@</font>NumMap<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>I<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Instanced Integer Filter!'</font><font color="red">);
</font><b>for </b>I <b>in </b>Int32Array<font color="red">.</font>Create<font color="red">(</font><font color="navy">1</font><font color="red">, </font><font color="navy">2</font><font color="red">, </font><font color="navy">3</font><font color="red">, </font><font color="navy">4</font><font color="red">, </font><font color="navy">5</font><font color="red">, </font><font color="navy">6</font><font color="red">, </font><font color="navy">7</font><font color="red">, </font><font color="navy">8</font><font color="red">, </font><font color="navy">9</font><font color="red">, </font><font color="navy">10</font><font color="red">).</font>Filter<font color="red">(@</font>NumFilter<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>I<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Instanced Integer Reduce!'</font><font color="red">);
</font>WriteLn<font color="red">(</font>Int32Array<font color="red">.</font>Create<font color="red">(</font><font color="navy">1</font><font color="red">, </font><font color="navy">2</font><font color="red">, </font><font color="navy">3</font><font color="red">, </font><font color="navy">4</font><font color="red">, </font><font color="navy">5</font><font color="red">, </font><font color="navy">6</font><font color="red">, </font><font color="navy">7</font><font color="red">, </font><font color="navy">8</font><font color="red">, </font><font color="navy">9</font><font color="red">, </font><font color="navy">10</font><font color="red">).</font>Reduce<font color="red">(@</font>NumReduce<font color="red">));
</font>WriteLn<font color="red">(</font><font color="blue">'Static Integer Map!'</font><font color="red">);
</font><b>for </b>I <b>in </b>Int32Array<font color="red">.</font>Map<font color="red">([</font><font color="navy">1</font><font color="red">, </font><font color="navy">2</font><font color="red">, </font><font color="navy">3</font><font color="red">, </font><font color="navy">4</font><font color="red">, </font><font color="navy">5</font><font color="red">, </font><font color="navy">6</font><font color="red">, </font><font color="navy">7</font><font color="red">, </font><font color="navy">8</font><font color="red">, </font><font color="navy">9</font><font color="red">, </font><font color="navy">10</font><font color="red">], @</font>NumMap<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>I<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Static Integer Filter!'</font><font color="red">);
</font><b>for </b>I <b>in </b>Int32Array<font color="red">.</font>Filter<font color="red">([</font><font color="navy">1</font><font color="red">, </font><font color="navy">2</font><font color="red">, </font><font color="navy">3</font><font color="red">, </font><font color="navy">4</font><font color="red">, </font><font color="navy">5</font><font color="red">, </font><font color="navy">6</font><font color="red">, </font><font color="navy">7</font><font color="red">, </font><font color="navy">8</font><font color="red">, </font><font color="navy">9</font><font color="red">, </font><font color="navy">10</font><font color="red">], @</font>NumFilter<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>I<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Static Integer Reduce!'</font><font color="red">);
</font>WriteLn<font color="red">(</font>Int32Array<font color="red">.</font>Reduce<font color="red">([</font><font color="navy">1</font><font color="red">, </font><font color="navy">2</font><font color="red">, </font><font color="navy">3</font><font color="red">, </font><font color="navy">4</font><font color="red">, </font><font color="navy">5</font><font color="red">, </font><font color="navy">6</font><font color="red">, </font><font color="navy">7</font><font color="red">, </font><font color="navy">8</font><font color="red">, </font><font color="navy">9</font><font color="red">, </font><font color="navy">10</font><font color="red">], @</font>NumReduce<font color="red">));
</font>WriteLn<font color="red">(</font><font color="blue">'Instanced String Map!'</font><font color="red">);
</font><b>for </b>S <b>in </b>AnsiStringArray<font color="red">.</font>Create<font color="red">(</font><font color="blue">'a'</font><font color="red">, </font><font color="blue">'b'</font><font color="red">, </font><font color="blue">'c'</font><font color="red">, </font><font color="blue">'d'</font><font color="red">, </font><font color="blue">'e'</font><font color="red">, </font><font color="blue">'f'</font><font color="red">, </font><font color="blue">'g'</font><font color="red">, </font><font color="blue">'h'</font><font color="red">, </font><font color="blue">'i'</font><font color="red">).</font>Map<font color="red">(@</font>StringMap<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>S<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Instanced String Filter!'</font><font color="red">);
</font><b>for </b>S <b>in </b>AnsiStringArray<font color="red">.</font>Create<font color="red">(</font><font color="blue">'a'</font><font color="red">, </font><font color="blue">'b'</font><font color="red">, </font><font color="blue">'c'</font><font color="red">, </font><font color="blue">'d'</font><font color="red">, </font><font color="blue">'e'</font><font color="red">, </font><font color="blue">'f'</font><font color="red">, </font><font color="blue">'g'</font><font color="red">, </font><font color="blue">'h'</font><font color="red">, </font><font color="blue">'i'</font><font color="red">).</font>Filter<font color="red">(@</font>StringFilter<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>S<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Instanced String Reduce!'</font><font color="red">);
</font>WriteLn<font color="red">(</font>AnsiStringArray<font color="red">.</font>Create<font color="red">(</font><font color="blue">'a'</font><font color="red">, </font><font color="blue">'b'</font><font color="red">, </font><font color="blue">'c'</font><font color="red">, </font><font color="blue">'d'</font><font color="red">, </font><font color="blue">'e'</font><font color="red">, </font><font color="blue">'f'</font><font color="red">, </font><font color="blue">'g'</font><font color="red">, </font><font color="blue">'h'</font><font color="red">, </font><font color="blue">'i'</font><font color="red">).</font>Reduce<font color="red">(@</font>StringReduce<font color="red">));
</font>WriteLn<font color="red">(</font><font color="blue">'Static String Map!'</font><font color="red">);
</font><b>for </b>S <b>in </b>AnsiStringArray<font color="red">.</font>Map<font color="red">([</font><font color="blue">'a'</font><font color="red">, </font><font color="blue">'b'</font><font color="red">, </font><font color="blue">'c'</font><font color="red">, </font><font color="blue">'d'</font><font color="red">, </font><font color="blue">'e'</font><font color="red">, </font><font color="blue">'f'</font><font color="red">, </font><font color="blue">'g'</font><font color="red">, </font><font color="blue">'h'</font><font color="red">, </font><font color="blue">'i'</font><font color="red">], @</font>StringMap<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>S<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Static String Filter!'</font><font color="red">);
</font><b>for </b>S <b>in </b>AnsiStringArray<font color="red">.</font>Filter<font color="red">([</font><font color="blue">'a'</font><font color="red">, </font><font color="blue">'b'</font><font color="red">, </font><font color="blue">'c'</font><font color="red">, </font><font color="blue">'d'</font><font color="red">, </font><font color="blue">'e'</font><font color="red">, </font><font color="blue">'f'</font><font color="red">, </font><font color="blue">'g'</font><font color="red">, </font><font color="blue">'h'</font><font color="red">, </font><font color="blue">'i'</font><font color="red">], @</font>StringFilter<font color="red">) </font><b>do </b>WriteLn<font color="red">(</font>S<font color="red">);
</font>WriteLn<font color="red">(</font><font color="blue">'Static String Reduce!'</font><font color="red">);
</font>WriteLn<font color="red">(</font>AnsiStringArray<font color="red">.</font>Reduce<font color="red">([</font><font color="blue">'a'</font><font color="red">, </font><font color="blue">'b'</font><font color="red">, </font><font color="blue">'c'</font><font color="red">, </font><font color="blue">'d'</font><font color="red">, </font><font color="blue">'e'</font><font color="red">, </font><font color="blue">'f'</font><font color="red">, </font><font color="blue">'g'</font><font color="red">, </font><font color="blue">'h'</font><font color="red">, </font><font color="blue">'i'</font><font color="red">], @</font>StringReduce<font color="red">));
</font><b>end</b><font color="red">.
</font></font></font></code></pre><br class="gmail-Apple-interchange-newline"></div></div>