<div dir="ltr"><div dir="ltr">On Thu, Jun 27, 2019 at 9:09 PM Ben Grasset <<a href="mailto:operator97@gmail.com">operator97@gmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><pre style="color:rgb(0,0,0)">-snip-</pre></div></div></blockquote><div>Yikes, I didn't realize the "preformatted" code from the Lazarus HTML exporter would show up with a bunch of asterisks outside of a real email client.</div><div><br></div><div>Here's normal text versions of both the unit, and the example program:</div><div><br></div>unit Functional;<br><br>{$mode Delphi}{$H+}<br><br>interface<br><br>type<br>  TArrayHelper<T> = record<br>  public type<br>    TMapModifier = function(constref Current: T): T;<br>    TFilterTest = function(constref Current: T): boolean;<br>    TReduceModifier = procedure(var Accumulator: T; constref Current: T);<br>    ArrayType = array of T;<br>    THelperImpl = record helper for ArrayType<br>      function Map(const Modifier: TMapModifier): ArrayType; overload;<br>      function Filter(const Test: TFilterTest): ArrayType; overload;<br>      function Reduce(const Modifier: TReduceModifier): T; overload;<br>      class function Map(constref Values: array of T; const Modifier: TMapModifier): ArrayType; static; overload;<br>      class function Filter(constref Values: array of T; const Test: TFilterTest): ArrayType; static; overload;<br>      class function Reduce(constref Values: array of T; const Modifier: TReduceModifier): T; static; overload;<br>    end;<br>  end;<br><br>  (* These are defined without the usual T prefix to avoid any conflict<br>     with possible existing type aliases. *)<br>  UInt8Array = TArrayHelper<Byte>.ArrayType;<br>  ShortIntArray = TArrayHelper<ShortInt>.ArrayType;<br>  SmallIntArray = TArrayHelper<SmallInt>.ArrayType;<br>  UInt16Array = TArrayHelper<Word>.ArrayType;<br>  UInt32Array = TArrayHelper<Cardinal>.ArrayType;<br>  Int32Array = TArrayHelper<LongInt>.ArrayType;<br>  Int64Array = TArrayHelper<Int64>.ArrayType;<br>  UInt64Array = TArrayHelper<QWord>.ArrayType;<br>  Float32Array = TArrayHelper<Single>.ArrayType;<br>  Float64Array = TArrayHelper<Double>.ArrayType;<br>  ShortStringArray = TArrayHelper<ShortString>.ArrayType;<br>  AnsiStringArray = TArrayHelper<AnsiString>.ArrayType;<br>  UnicodeStringArray = TArrayHelper<UnicodeString>.ArrayType;<br><br>implementation<br><br>function TArrayHelper<T>.THelperImpl.Map(const Modifier: TMapModifier): ArrayType;<br>var I: PtrUInt;<br>begin<br>  SetLength(Result, Length(Self));<br>  for I := 0 to High(Self) do<br>    Result[I] := Modifier(Self[I]);<br>end;<br><br>function TArrayHelper<T>.THelperImpl.Filter(const Test: TFilterTest): ArrayType;<br>var I, J: PtrUInt;<br>begin<br>  J := 0;<br>  SetLength(Result, Length(Self));<br>  for I := 0 to High(Self) do<br>    if Test(Self[I]) then begin<br>      Result[J] := Self[I];<br>      Inc(J);<br>    end;<br>  SetLength(Result, J);<br>end;<br><br>function TArrayHelper<T>.THelperImpl.Reduce(const Modifier: TReduceModifier): T;<br>var I: PtrUInt;<br>begin<br>  Result := Self[0];<br>  for I := 1 to High(Self) do<br>    Modifier(Result, Self[I]);<br>end;<br><br>class function TArrayHelper<T>.THelperImpl.Map(constref Values: array of T; const Modifier: TMapModifier): ArrayType;<br>var I: PtrUInt;<br>begin<br>  SetLength(Result, Length(Values));<br>  for I := 0 to High(Values) do<br>    Result[I] := Modifier(Values[I]);<br>end;<br><br>class function TArrayHelper<T>.THelperImpl.Filter(constref Values: array of T; const Test: TFilterTest): ArrayType;<br>var I, J: PtrUInt;<br>begin<br>  J := 0;<br>  SetLength(Result, Length(Values));<br>  for I := 0 to High(Values) do<br>    if Test(Values[I]) then begin<br>      Result[J] := Values[I];<br>      Inc(J);<br>    end;<br>  SetLength(Result, J);<br>end;<br><br>class function TArrayHelper<T>.THelperImpl.Reduce(constref Values: array of T; const Modifier: TReduceModifier): T;<br>var I: PtrUInt;<br>begin<br>  Result := Values[0];<br>  for I := 1 to High(Values) do<br>    Modifier(Result, Values[I]);<br>end;<br><br><div>end.</div><div><br></div><div>///////////////</div><div><br></div><div>program TestFunctional;<br><br>{$mode ObjFPC}{$H+}<br><br>uses Functional;<br><br>function NumMap(constref Current: LongInt): LongInt;<br>begin<br>  Result := Current + Current;<br>end;<br><br>function NumFilter(constref Current: LongInt): Boolean;<br>begin<br>  Result := Current > 5;<br>end;<br><br>procedure NumReduce(var Accumulator: LongInt; constref Current: LongInt);<br>begin<br>  Accumulator += Current;<br>end;<br><br>function StringMap(constref Current: AnsiString): AnsiString;<br>begin<br>  Result := Current + Current;<br>end;<br><br>function StringFilter(constref Current: AnsiString): boolean;<br>begin<br>  Result := Current > 'e';<br>end;<br><br>procedure StringReduce(var Accumulator: AnsiString; constref Current: AnsiString);<br>begin<br>  Accumulator += Current;<br>end;<br><br>var<br>  I: LongInt;<br>  S: AnsiString;<br><br>begin<br>  WriteLn('Instanced Integer Map!');<br>  for I in Int32Array.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Map(@NumMap) do WriteLn(I);<br><br>  WriteLn('Instanced Integer Filter!');<br>  for I in Int32Array.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Filter(@NumFilter) do WriteLn(I);<br><br>  WriteLn('Instanced Integer Reduce!');<br>  WriteLn(Int32Array.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Reduce(@NumReduce));<br><br>  WriteLn('Static Integer Map!');<br>  for I in Int32Array.Map([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @NumMap) do WriteLn(I);<br><br>  WriteLn('Static Integer Filter!');<br>  for I in Int32Array.Filter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @NumFilter) do WriteLn(I);<br><br>  WriteLn('Static Integer Reduce!');<br>  WriteLn(Int32Array.Reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @NumReduce));<br><br>  WriteLn('Instanced String Map!');<br>  for S in AnsiStringArray.Create('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i').Map(@StringMap) do WriteLn(S);<br><br>  WriteLn('Instanced String Filter!');<br>  for S in AnsiStringArray.Create('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i').Filter(@StringFilter) do WriteLn(S);<br><br>  WriteLn('Instanced String Reduce!');<br>  WriteLn(AnsiStringArray.Create('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i').Reduce(@StringReduce));<br><br>  WriteLn('Static String Map!');<br>  for S in AnsiStringArray.Map(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], @StringMap) do WriteLn(S);<br><br>  WriteLn('Static String Filter!');<br>  for S in AnsiStringArray.Filter(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], @StringFilter) do WriteLn(S);<br><br>  WriteLn('Static String Reduce!');<br>  WriteLn(AnsiStringArray.Reduce(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], @StringReduce));<br>end.<br></div></div></div>