├── demo ├── data │ └── employee.cds ├── SeqDemo.dpr ├── fmMain.dfm ├── SeqDemo.dproj └── fmMain.pas ├── .gitignore ├── src ├── Functional.Value.pas ├── Functional.FuncFactory.pas └── Functional.Sequence.pas └── LICENSE.txt /demo/data/employee.cds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colinj/Functional/HEAD/demo/data/employee.cds -------------------------------------------------------------------------------- /demo/SeqDemo.dpr: -------------------------------------------------------------------------------- 1 | program SeqDemo; 2 | 3 | uses 4 | Forms, 5 | fmMain in 'fmMain.pas' {FrmDemo}, 6 | Functional.FuncFactory in '..\src\Functional.FuncFactory.pas', 7 | Functional.Sequence in '..\src\Functional.Sequence.pas', 8 | Functional.Value in '..\src\Functional.Value.pas'; 9 | 10 | {$R *.res} 11 | 12 | begin 13 | Application.Initialize; 14 | Application.MainFormOnTaskbar := True; 15 | Application.CreateForm(TFrmDemo, FrmDemo); 16 | Application.Run; 17 | end. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __history/ 2 | Thumbs.db 3 | .DS_Store 4 | *.~* 5 | *.bak 6 | *.BAK 7 | *.cfg 8 | *.CFG 9 | *.chm 10 | *.db 11 | *.DB 12 | *.dcu 13 | *.DCU 14 | *.ddp 15 | *.dll 16 | *.DLL 17 | *.dof 18 | *.DOF 19 | *.dres 20 | *.dsk 21 | *.DSK 22 | *.dti 23 | *.exe 24 | *.EXE 25 | *.fam 26 | *.FAM 27 | *.gid 28 | *.GID 29 | *.hlp 30 | *.HLP 31 | *.identcache 32 | *.local 33 | *.log 34 | *.map 35 | *.MAP 36 | *.mb 37 | *.MB 38 | *.net 39 | *.NET 40 | *.obj 41 | *.OBJ 42 | *.opt 43 | *.OPT 44 | *.px 45 | *.PX 46 | *.res 47 | *.RES 48 | *.scc 49 | *.tsl 50 | *.tsr 51 | *.tv 52 | *.TV 53 | *.val 54 | *.VAL 55 | *.[Xx]0* 56 | *.[Yy]0* 57 | *.[Xx][Gg]* 58 | *.[Yy][Gg]* 59 | *.zip 60 | *.ZIP 61 | -------------------------------------------------------------------------------- /src/Functional.Value.pas: -------------------------------------------------------------------------------- 1 | {****************************************************} 2 | { } 3 | { Delphi Functional Library } 4 | { } 5 | { Copyright (C) 2015 Colin Johnsun } 6 | { } 7 | { https:/github.com/colinj } 8 | { } 9 | {****************************************************} 10 | { } 11 | { This Source Code Form is subject to the terms of } 12 | { the Mozilla Public License, v. 2.0. If a copy of } 13 | { the MPL was not distributed with this file, You } 14 | { can obtain one at } 15 | { } 16 | { http://mozilla.org/MPL/2.0/ } 17 | { } 18 | {****************************************************} 19 | 20 | unit Functional.Value; 21 | 22 | interface 23 | 24 | uses 25 | SysUtils, Classes; 26 | 27 | type 28 | TValueState = (vsStart, vsSomething, vsNothing, vsFinish); 29 | 30 | TValue = record 31 | private 32 | FValue: T; 33 | FState: TValueState; 34 | public 35 | class operator Implicit(const aValue: T): TValue; 36 | class function Nothing: TValue; static; 37 | class function Start: TValue; static; 38 | class function Finish: TValue; static; 39 | function HasValue: Boolean; 40 | procedure SetState(const aState: TValueState); 41 | property Value: T read FValue; 42 | property State: TValueState read FState; 43 | end; 44 | 45 | implementation 46 | 47 | { TValue } 48 | 49 | class operator TValue.Implicit(const aValue: T): TValue; 50 | begin 51 | Result.FValue := aValue; 52 | Result.FState := vsSomething; 53 | end; 54 | 55 | function TValue.HasValue: Boolean; 56 | begin 57 | Result := FState = vsSomething; 58 | end; 59 | 60 | class function TValue.Nothing: TValue; 61 | begin 62 | Result.FState := vsNothing; 63 | end; 64 | 65 | procedure TValue.SetState(const aState: TValueState); 66 | begin 67 | FState := aState; 68 | end; 69 | 70 | class function TValue.Start: TValue; 71 | begin 72 | Result.FState := vsStart; 73 | end; 74 | 75 | class function TValue.Finish: TValue; 76 | begin 77 | Result.FState := vsFinish; 78 | end; 79 | 80 | end. 81 | -------------------------------------------------------------------------------- /src/Functional.FuncFactory.pas: -------------------------------------------------------------------------------- 1 | {****************************************************} 2 | { } 3 | { Delphi Functional Library } 4 | { } 5 | { Copyright (C) 2015 Colin Johnsun } 6 | { } 7 | { https:/github.com/colinj } 8 | { } 9 | {****************************************************} 10 | { } 11 | { This Source Code Form is subject to the terms of } 12 | { the Mozilla Public License, v. 2.0. If a copy of } 13 | { the MPL was not distributed with this file, You } 14 | { can obtain one at } 15 | { } 16 | { http://mozilla.org/MPL/2.0/ } 17 | { } 18 | {****************************************************} 19 | 20 | unit Functional.FuncFactory; 21 | 22 | interface 23 | 24 | uses 25 | SysUtils, Classes, 26 | Generics.Collections, 27 | Functional.Value; 28 | 29 | type 30 | TPredicate = reference to function (const Arg1: T): Boolean; 31 | TValueFunc = reference to function (const Item: TValue): TValue; 32 | TIteratorProc = reference to procedure (const P: TPredicate); 33 | TFoldFunc = reference to function (const Item: T; const Acc: U): U; 34 | 35 | TFuncFactory = record 36 | public 37 | class function CreateFilter(const aFunc: TValueFunc; const aPredicate: TPredicate): TValueFunc; static; 38 | class function CreateMap(const aFunc: TValueFunc; const aMapper: TFunc): TValueFunc; static; 39 | class function CreateTake(const aFunc: TValueFunc; const aCount: Integer): TValueFunc; static; 40 | class function CreateSkip(const aFunc: TValueFunc; const aCount: Integer): TValueFunc; static; 41 | class function CreateTakeWhile(const aFunc: TValueFunc; const aPredicate: TPredicate): TValueFunc; static; 42 | class function CreateSkipWhile(const aFunc: TValueFunc; const aPredicate: TPredicate): TValueFunc; static; 43 | 44 | class function ForEach(const aFunc: TValueFunc; const aAction: TProc): TPredicate; static; 45 | class function AddItem(const aFunc: TValueFunc; const aList: TList): TPredicate; static; 46 | end; 47 | 48 | implementation 49 | 50 | class function TFuncFactory.ForEach(const aFunc: TValueFunc; const aAction: TProc): TPredicate; 51 | begin 52 | Result := 53 | function (const Item: T): Boolean 54 | var 55 | R: TValue; 56 | begin 57 | Result := False; 58 | R := aFunc(TValue(Item)); 59 | case R.State of 60 | vsSomething: aAction(R.Value); 61 | vsFinish: Result := True; 62 | end; 63 | end; 64 | end; 65 | 66 | class function TFuncFactory.AddItem(const aFunc: TValueFunc; const aList: TList): TPredicate; 67 | var 68 | ItemList: TList; 69 | begin 70 | ItemList := aList; 71 | 72 | Result := 73 | function (const Item: T): Boolean 74 | var 75 | R: TValue; 76 | begin 77 | R := aFunc(TValue(Item)); 78 | if R.HasValue then 79 | ItemList.Add(R.Value); 80 | Result := R.State = vsFinish; 81 | end; 82 | end; 83 | 84 | class function TFuncFactory.CreateFilter(const aFunc: TValueFunc; const aPredicate: TPredicate): TValueFunc; 85 | begin 86 | Result := 87 | function (const Item: TValue): TValue 88 | begin 89 | Result := aFunc(Item); 90 | if Result.HasValue and not aPredicate(Result.Value) then 91 | Result := TValue.Nothing; 92 | end; 93 | end; 94 | 95 | class function TFuncFactory.CreateMap(const aFunc: TValueFunc; const aMapper: TFunc): TValueFunc; 96 | begin 97 | Result := 98 | function (const Item: TValue): TValue 99 | var 100 | R: TValue; 101 | begin 102 | R := aFunc(Item); 103 | if R.HasValue then 104 | Result := TValue(aMapper(R.Value)) 105 | else 106 | Result.SetState(R.State); 107 | end; 108 | end; 109 | 110 | class function TFuncFactory.CreateSkip(const aFunc: TValueFunc; const aCount: Integer): TValueFunc; 111 | var 112 | Counter: Integer; 113 | begin 114 | Result := 115 | function (const Item: TValue): TValue 116 | begin 117 | Result := aFunc(Item); 118 | case Result.State of 119 | vsStart: Counter := 0; 120 | vsSomething: 121 | begin 122 | Inc(Counter); 123 | if Counter <= aCount then 124 | Result := TValue.Nothing; 125 | end; 126 | end; 127 | end; 128 | end; 129 | 130 | class function TFuncFactory.CreateSkipWhile(const aFunc: TValueFunc; const aPredicate: TPredicate): TValueFunc; 131 | var 132 | Skipping: Boolean; 133 | begin 134 | Result := 135 | function (const Item: TValue): TValue 136 | begin 137 | Result := aFunc(Item); 138 | 139 | case Result.State of 140 | vsStart: Skipping := True; 141 | vsSomething: 142 | begin 143 | if Skipping then 144 | begin 145 | if aPredicate(Result.Value) then 146 | Result := TValue.Nothing 147 | else 148 | Skipping := False; 149 | end; 150 | end; 151 | end; 152 | end; 153 | end; 154 | 155 | class function TFuncFactory.CreateTake(const aFunc: TValueFunc; const aCount: Integer): TValueFunc; 156 | var 157 | Counter: Integer; 158 | begin 159 | Result := 160 | function (const Item: TValue): TValue 161 | begin 162 | if Counter = aCount then 163 | begin 164 | Result := TValue.Finish; 165 | Exit; 166 | end; 167 | 168 | Result := aFunc(Item); 169 | case Result.State of 170 | vsStart: Counter := 0; 171 | vsSomething: Inc(Counter); 172 | end; 173 | end; 174 | end; 175 | 176 | class function TFuncFactory.CreateTakeWhile(const aFunc: TValueFunc; const aPredicate: TPredicate): TValueFunc; 177 | begin 178 | Result := 179 | function (const Item: TValue): TValue 180 | begin 181 | Result := aFunc(Item); 182 | if Result.HasValue and not aPredicate(Result.Value) then 183 | Result := TValue.Finish; 184 | end; 185 | end; 186 | 187 | end. 188 | -------------------------------------------------------------------------------- /demo/fmMain.dfm: -------------------------------------------------------------------------------- 1 | object FrmDemo: TFrmDemo 2 | Left = 0 3 | Top = 0 4 | Caption = 'Sequence Demo' 5 | ClientHeight = 528 6 | ClientWidth = 806 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | OnCreate = FormCreate 15 | PixelsPerInch = 96 16 | TextHeight = 13 17 | object PageControl1: TPageControl 18 | AlignWithMargins = True 19 | Left = 3 20 | Top = 3 21 | Width = 198 22 | Height = 522 23 | ActivePage = TabSheet1 24 | Align = alLeft 25 | TabOrder = 0 26 | object TabSheet1: TTabSheet 27 | Caption = 'TSequence' 28 | object Button1: TButton 29 | Left = 32 30 | Top = 24 31 | Width = 120 32 | Height = 25 33 | Action = actDemo01 34 | TabOrder = 0 35 | end 36 | object Button2: TButton 37 | Left = 32 38 | Top = 55 39 | Width = 120 40 | Height = 25 41 | Action = actDemo02 42 | TabOrder = 1 43 | end 44 | object Button3: TButton 45 | Left = 32 46 | Top = 86 47 | Width = 120 48 | Height = 25 49 | Action = actDemo03A 50 | TabOrder = 2 51 | end 52 | object Button4: TButton 53 | Left = 32 54 | Top = 117 55 | Width = 120 56 | Height = 25 57 | Action = actDemo03B 58 | TabOrder = 3 59 | end 60 | object Button5: TButton 61 | Left = 32 62 | Top = 148 63 | Width = 120 64 | Height = 25 65 | Action = actDemo04 66 | TabOrder = 4 67 | end 68 | object Button9: TButton 69 | Left = 32 70 | Top = 179 71 | Width = 120 72 | Height = 25 73 | Action = actDemo05 74 | TabOrder = 5 75 | end 76 | object Button6: TButton 77 | Left = 32 78 | Top = 210 79 | Width = 120 80 | Height = 25 81 | Action = actDemo06 82 | TabOrder = 6 83 | end 84 | object Button7: TButton 85 | Left = 32 86 | Top = 241 87 | Width = 120 88 | Height = 25 89 | Action = actDemo07 90 | TabOrder = 7 91 | end 92 | object Button8: TButton 93 | Left = 32 94 | Top = 272 95 | Width = 120 96 | Height = 25 97 | Action = actDemo08 98 | TabOrder = 8 99 | end 100 | object Button11: TButton 101 | Left = 32 102 | Top = 303 103 | Width = 120 104 | Height = 25 105 | Action = actDemo09 106 | TabOrder = 9 107 | end 108 | object btnContinue: TButton 109 | Left = 32 110 | Top = 391 111 | Width = 120 112 | Height = 25 113 | Caption = 'Continue' 114 | TabOrder = 10 115 | OnClick = btnContinueClick 116 | end 117 | end 118 | object TabSheet5: TTabSheet 119 | Caption = 'DataSet' 120 | ImageIndex = 2 121 | object Button10: TButton 122 | Left = 24 123 | Top = 20 124 | Width = 75 125 | Height = 25 126 | Caption = 'Button5' 127 | TabOrder = 0 128 | OnClick = Button5Click 129 | end 130 | object btnDsLoop: TButton 131 | Left = 24 132 | Top = 64 133 | Width = 75 134 | Height = 25 135 | Caption = 'Loop' 136 | TabOrder = 1 137 | OnClick = btnDsLoopClick 138 | end 139 | end 140 | end 141 | object Panel1: TPanel 142 | Left = 204 143 | Top = 0 144 | Width = 602 145 | Height = 528 146 | Align = alClient 147 | Caption = 'Panel1' 148 | TabOrder = 1 149 | object PageControl2: TPageControl 150 | AlignWithMargins = True 151 | Left = 4 152 | Top = 4 153 | Width = 594 154 | Height = 520 155 | ActivePage = TabSheet3 156 | Align = alClient 157 | TabOrder = 0 158 | object TabSheet3: TTabSheet 159 | Caption = 'Log' 160 | object Memo1: TMemo 161 | Left = 0 162 | Top = 0 163 | Width = 586 164 | Height = 492 165 | Align = alClient 166 | Font.Charset = DEFAULT_CHARSET 167 | Font.Color = clWindowText 168 | Font.Height = -13 169 | Font.Name = 'Consolas' 170 | Font.Style = [] 171 | ParentFont = False 172 | ScrollBars = ssVertical 173 | TabOrder = 0 174 | end 175 | end 176 | object TabSheet4: TTabSheet 177 | Caption = 'DataSet' 178 | ImageIndex = 1 179 | object DBGrid1: TDBGrid 180 | Left = 0 181 | Top = 0 182 | Width = 586 183 | Height = 492 184 | Align = alClient 185 | DataSource = DataSource1 186 | TabOrder = 0 187 | TitleFont.Charset = DEFAULT_CHARSET 188 | TitleFont.Color = clWindowText 189 | TitleFont.Height = -11 190 | TitleFont.Name = 'Tahoma' 191 | TitleFont.Style = [] 192 | end 193 | end 194 | end 195 | end 196 | object ClientDataSet1: TClientDataSet 197 | Aggregates = <> 198 | FileName = 'data\employee.cds' 199 | Params = <> 200 | Left = 640 201 | Top = 144 202 | end 203 | object DataSource1: TDataSource 204 | DataSet = ClientDataSet1 205 | Left = 640 206 | Top = 200 207 | end 208 | object atlDemo: TActionList 209 | Left = 640 210 | Top = 72 211 | object actDemo01: TAction 212 | Caption = 'ForEach' 213 | OnExecute = actDemo01Execute 214 | end 215 | object actDemo02: TAction 216 | Caption = 'Where / Filter' 217 | OnExecute = actDemo02Execute 218 | end 219 | object actDemo03A: TAction 220 | Caption = 'Select / Map' 221 | OnExecute = actDemo03AExecute 222 | end 223 | object actDemo03B: TAction 224 | Caption = 'Select / Map (2)' 225 | OnExecute = actDemo03BExecute 226 | end 227 | object actDemo04: TAction 228 | Caption = 'Take && Skip' 229 | OnExecute = actDemo04Execute 230 | end 231 | object actDemo05: TAction 232 | Caption = 'TakeWhile' 233 | OnExecute = actDemo05Execute 234 | end 235 | object actDemo06: TAction 236 | Caption = 'SkipWhile' 237 | OnExecute = actDemo06Execute 238 | end 239 | object actDemo07: TAction 240 | Caption = 'Fold' 241 | OnExecute = actDemo07Execute 242 | end 243 | object actDemo08: TAction 244 | Caption = 'String Demo' 245 | OnExecute = actDemo08Execute 246 | end 247 | object actDemo09: TAction 248 | Caption = 'TStrings Demo' 249 | OnExecute = actDemo09Execute 250 | end 251 | end 252 | end 253 | -------------------------------------------------------------------------------- /demo/SeqDemo.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {5540AA26-C13C-470C-8205-5852179FF00B} 4 | SeqDemo.dpr 5 | True 6 | Debug 7 | 1 8 | Application 9 | VCL 10 | 13.4 11 | Win32 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Cfg_1 29 | true 30 | true 31 | 32 | 33 | true 34 | Base 35 | true 36 | 37 | 38 | true 39 | Cfg_2 40 | true 41 | true 42 | 43 | 44 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= 45 | None 46 | 3081 47 | Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace) 48 | 00400000 49 | false 50 | false 51 | false 52 | ../dcu 53 | false 54 | false 55 | 56 | 57 | true 58 | System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 59 | 1033 60 | $(BDS)\bin\default_app.manifest 61 | 62 | 63 | false 64 | false 65 | 0 66 | RELEASE;$(DCC_Define) 67 | 68 | 69 | true 70 | $(BDS)\bin\default_app.manifest 71 | 1033 72 | 73 | 74 | DEBUG;$(DCC_Define) 75 | false 76 | true 77 | 78 | 79 | $(BDS)\bin\default_app.manifest 80 | true 81 | 1033 82 | 83 | 84 | 85 | MainSource 86 | 87 | 88 |
FrmDemo
89 |
90 | 91 | 92 | 93 | 94 | Cfg_2 95 | Base 96 | 97 | 98 | Base 99 | 100 | 101 | Cfg_1 102 | Base 103 | 104 |
105 | 106 | Delphi.Personality.12 107 | 108 | 109 | 110 | 111 | SeqDemo.dpr 112 | 113 | 114 | False 115 | False 116 | 1 117 | 0 118 | 0 119 | 0 120 | False 121 | False 122 | False 123 | False 124 | False 125 | 3081 126 | 1252 127 | 128 | 129 | 130 | 131 | 1.0.0.0 132 | 133 | 134 | 135 | 136 | 137 | 1.0.0.0 138 | 139 | 140 | 141 | Microsoft Office 2000 Sample Automation Server Wrapper Components 142 | Microsoft Office XP Sample Automation Server Wrapper Components 143 | 144 | 145 | 146 | False 147 | True 148 | 149 | 150 | 12 151 | 152 | 153 | 154 |
155 | -------------------------------------------------------------------------------- /src/Functional.Sequence.pas: -------------------------------------------------------------------------------- 1 | {****************************************************} 2 | { } 3 | { Delphi Functional Library } 4 | { } 5 | { Copyright (C) 2015 Colin Johnsun } 6 | { } 7 | { https:/github.com/colinj } 8 | { } 9 | {****************************************************} 10 | { } 11 | { This Source Code Form is subject to the terms of } 12 | { the Mozilla Public License, v. 2.0. If a copy of } 13 | { the MPL was not distributed with this file, You } 14 | { can obtain one at } 15 | { } 16 | { http://mozilla.org/MPL/2.0/ } 17 | { } 18 | {****************************************************} 19 | 20 | unit Functional.Sequence; 21 | 22 | interface 23 | 24 | uses 25 | SysUtils, Classes, 26 | Generics.Collections, 27 | DB, 28 | Functional.Value, 29 | Functional.FuncFactory; 30 | 31 | type 32 | TSeq = record 33 | private 34 | FFunc: TValueFunc; 35 | FIterate: TIteratorProc; 36 | function CreateSeq(const aFunc: TValueFunc): TSeq; 37 | public 38 | function Filter(const aPredicate: TPredicate): TSeq; 39 | function Where(const aPredicate: TPredicate): TSeq; // synonym for Filter function 40 | function Map(const aMapper: TFunc): TSeq; overload; 41 | function Map(const aMapper: TFunc): TSeq; overload; 42 | function Select(const aMapper: TFunc): TSeq; overload; // synonum for Map function 43 | function Select(const aMapper: TFunc): TSeq; overload; // synonym for Map function 44 | function Take(const aCount: Integer): TSeq; 45 | function Skip(const aCount: Integer): TSeq; 46 | function TakeWhile(const aPredicate: TPredicate): TSeq; 47 | function SkipWhile(const aPredicate: TPredicate): TSeq; 48 | function Fold(const aFoldFunc: TFoldFunc; const aInitVal: TResult): TResult; 49 | function ToList: TList; 50 | procedure ForEach(const aAction: TProc); 51 | end; 52 | 53 | TSeq = record 54 | private 55 | FFunc: TValueFunc; 56 | FIterate: TIteratorProc; 57 | function CreateSeq(const aFunc: TValueFunc): TSeq; 58 | public 59 | function Filter(const aPredicate: TPredicate): TSeq; 60 | function Where(const aPredicate: TPredicate): TSeq; // synonym for Filter function 61 | function Map(const aMapper: TFunc): TSeq; overload; 62 | function Map(const aMapper: TFunc): TSeq; overload; 63 | function Select(const aMapper: TFunc): TSeq; overload; // synonum for Map function 64 | function Select(const aMapper: TFunc): TSeq; overload; // synonym for Map function 65 | function Take(const aCount: Integer): TSeq; 66 | function Skip(const aCount: Integer): TSeq; 67 | function TakeWhile(const aPredicate: TPredicate): TSeq; 68 | function SkipWhile(const aPredicate: TPredicate): TSeq; 69 | function Fold(const aFoldFunc: TFoldFunc; const aInitVal: TResult): TResult; 70 | function ToList: TList; 71 | procedure ForEach(const aAction: TProc); 72 | end; 73 | 74 | TSeq = record 75 | public 76 | class function Identity(const Item: TValue): TValue; static; 77 | class function From(const aArray: TArray): TSeq; overload; static; 78 | class function From(const aEnumerable: TEnumerable): TSeq; overload; static; 79 | class function From(const aString: string): TSeq; overload; static; 80 | class function From(const aStrings: TStrings): TSeq; overload; static; 81 | class function From(const aDataset: TDataSet): TSeq; overload; static; 82 | class function Range(const aStart, aFinish: Integer): TSeq; static; 83 | end; 84 | 85 | implementation 86 | 87 | { TSeq } 88 | 89 | function TSeq.CreateSeq(const aFunc: TValueFunc): TSeq; 90 | begin 91 | Result.FFunc := aFunc; 92 | Result.FIterate := FIterate; 93 | end; 94 | 95 | function TSeq.Filter(const aPredicate: TPredicate): TSeq; 96 | begin 97 | Result := CreateSeq(TFuncFactory.CreateFilter(FFunc, aPredicate)); 98 | end; 99 | 100 | function TSeq.Where(const aPredicate: TPredicate): TSeq; 101 | begin 102 | Result := Filter(aPredicate); 103 | end; 104 | 105 | function TSeq.Map(const aMapper: TFunc): TSeq; 106 | begin 107 | Result := CreateSeq(TFuncFactory.CreateMap(FFunc, aMapper)); 108 | end; 109 | 110 | function TSeq.Map(const aMapper: TFunc): TSeq; 111 | begin 112 | Result.FFunc := TFuncFactory.CreateMap(FFunc, aMapper); 113 | Result.FIterate := FIterate; 114 | end; 115 | 116 | function TSeq.Select(const aMapper: TFunc): TSeq; 117 | begin 118 | Result := Map(aMapper); 119 | end; 120 | 121 | function TSeq.Select(const aMapper: TFunc): TSeq; 122 | begin 123 | Result := Map(aMapper); 124 | end; 125 | 126 | function TSeq.Take(const aCount: Integer): TSeq; 127 | begin 128 | Result := CreateSeq(TFuncFactory.CreateTake(FFunc, aCount)); 129 | end; 130 | 131 | function TSeq.TakeWhile(const aPredicate: TPredicate): TSeq; 132 | begin 133 | Result := CreateSeq(TFuncFactory.CreateTakeWhile(FFunc, aPredicate)); 134 | end; 135 | 136 | function TSeq.Skip(const aCount: Integer): TSeq; 137 | begin 138 | Result := CreateSeq(TFuncFactory.CreateSkip(FFunc, aCount)); 139 | end; 140 | 141 | function TSeq.SkipWhile(const aPredicate: TPredicate): TSeq; 142 | begin 143 | Result := CreateSeq(TFuncFactory.CreateSkipWhile(FFunc, aPredicate)); 144 | end; 145 | 146 | procedure TSeq.ForEach(const aAction: TProc); 147 | begin 148 | FFunc(TValue.Start); 149 | FIterate(TFuncFactory.ForEach(FFunc, aAction)); 150 | end; 151 | 152 | function TSeq.ToList: TList; 153 | begin 154 | Result := TList.Create; 155 | FIterate(TFuncFactory.AddItem(FFunc, Result)); 156 | end; 157 | 158 | function TSeq.Fold(const aFoldFunc: TFoldFunc; const aInitVal: TResult): TResult; 159 | var 160 | OrigFunc: TValueFunc; 161 | Accumulator: TResult; 162 | begin 163 | OrigFunc := FFunc; 164 | 165 | Accumulator := aInitVal; 166 | OrigFunc(TValue.Start); 167 | 168 | FIterate( 169 | function (const Item: T): Boolean 170 | var 171 | R: TValue; 172 | begin 173 | Result := False; 174 | R := OrigFunc(TValue(Item)); 175 | case R.State of 176 | vsSomething: Accumulator := aFoldFunc(R.Value, Accumulator); 177 | vsFinish: Result := True; 178 | end; 179 | end 180 | ); 181 | 182 | Result := Accumulator; 183 | end; 184 | 185 | { TSeq } 186 | 187 | function TSeq.CreateSeq(const aFunc: TValueFunc): TSeq; 188 | begin 189 | Result.FFunc := aFunc; 190 | Result.FIterate := FIterate; 191 | end; 192 | 193 | function TSeq.Filter(const aPredicate: TPredicate): TSeq; 194 | begin 195 | Result := CreateSeq(TFuncFactory.CreateFilter(FFunc, aPredicate)); 196 | end; 197 | 198 | function TSeq.Where(const aPredicate: TPredicate): TSeq; 199 | begin 200 | Result := Filter(aPredicate); 201 | end; 202 | 203 | function TSeq.Map(const aMapper: TFunc): TSeq; 204 | begin 205 | Result := CreateSeq(TFuncFactory.CreateMap(FFunc, aMapper)); 206 | end; 207 | 208 | function TSeq.Map(const aMapper: TFunc): TSeq; 209 | begin 210 | Result.FFunc := TFuncFactory.CreateMap(FFunc, aMapper); 211 | Result.FIterate := FIterate; 212 | end; 213 | 214 | function TSeq.Select(const aMapper: TFunc): TSeq; 215 | begin 216 | Result := Map(aMapper); 217 | end; 218 | 219 | function TSeq.Select(const aMapper: TFunc): TSeq; 220 | begin 221 | Result := Map(aMapper); 222 | end; 223 | 224 | function TSeq.Take(const aCount: Integer): TSeq; 225 | begin 226 | Result := CreateSeq(TFuncFactory.CreateTake(FFunc, aCount)); 227 | end; 228 | 229 | function TSeq.TakeWhile(const aPredicate: TPredicate): TSeq; 230 | begin 231 | Result := CreateSeq(TFuncFactory.CreateTakeWhile(FFunc, aPredicate)); 232 | end; 233 | 234 | function TSeq.Skip(const aCount: Integer): TSeq; 235 | begin 236 | Result := CreateSeq(TFuncFactory.CreateSkip(FFunc, aCount)); 237 | end; 238 | 239 | function TSeq.SkipWhile(const aPredicate: TPredicate): TSeq; 240 | begin 241 | Result := CreateSeq(TFuncFactory.CreateSkipWhile(FFunc, aPredicate)); 242 | end; 243 | 244 | procedure TSeq.ForEach(const aAction: TProc); 245 | begin 246 | FFunc(TValue.Start); 247 | FIterate(TFuncFactory.ForEach(FFunc, aAction)); 248 | end; 249 | 250 | function TSeq.ToList: TList; 251 | begin 252 | Result := TList.Create; 253 | FIterate(TFuncFactory.AddItem(FFunc, Result)); 254 | end; 255 | 256 | function TSeq.Fold(const aFoldFunc: TFoldFunc; const aInitVal: TResult): TResult; 257 | var 258 | OrigFunc: TValueFunc; 259 | Accumulator: TResult; 260 | begin 261 | OrigFunc := FFunc; 262 | 263 | Accumulator := aInitVal; 264 | OrigFunc(TValue.Start); 265 | 266 | FIterate( 267 | function (const Item: T): Boolean 268 | var 269 | R: TValue; 270 | begin 271 | Result := False; 272 | R := OrigFunc(TValue(Item)); 273 | case R.State of 274 | vsSomething: Accumulator := aFoldFunc(R.Value, Accumulator); 275 | vsFinish: Result := True; 276 | end; 277 | end 278 | ); 279 | 280 | Result := Accumulator; 281 | end; 282 | 283 | { TSeq } 284 | 285 | class function TSeq.Identity(const Item: TValue): TValue; 286 | begin 287 | Result := Item; 288 | end; 289 | 290 | class function TSeq.From(const aArray: TArray): TSeq; 291 | begin 292 | Result.FFunc := Identity; 293 | Result.FIterate := 294 | procedure (const StopOn: TPredicate) 295 | var 296 | Item: T; 297 | begin 298 | for Item in aArray do 299 | if StopOn(Item) then Break; 300 | end; 301 | end; 302 | 303 | class function TSeq.From(const aEnumerable: TEnumerable): TSeq; 304 | begin 305 | Result.FFunc := Identity; 306 | Result.FIterate := 307 | procedure (const StopOn: TPredicate) 308 | var 309 | Item: T; 310 | begin 311 | for Item in aEnumerable do 312 | if StopOn(Item) then Break; 313 | end; 314 | end; 315 | 316 | class function TSeq.From(const aString: string): TSeq; 317 | begin 318 | Result.FFunc := Identity; 319 | Result.FIterate := 320 | procedure (const StopOn: TPredicate) 321 | var 322 | Item: Char; 323 | begin 324 | for Item in aString do 325 | if StopOn(Item) then Break; 326 | end; 327 | end; 328 | 329 | class function TSeq.From(const aStrings: TStrings): TSeq; 330 | begin 331 | Result.FFunc := Identity; 332 | Result.FIterate := 333 | procedure (const StopOn: TPredicate) 334 | var 335 | Item: string; 336 | begin 337 | for Item in aStrings do 338 | if StopOn(Item) then Break; 339 | end; 340 | end; 341 | 342 | class function TSeq.From(const aDataset: TDataSet): TSeq; 343 | begin 344 | Result.FFunc := Identity; 345 | Result.FIterate := 346 | procedure (const StopOn: TPredicate) 347 | var 348 | D: TDataSet; 349 | begin 350 | D := aDataset; 351 | D.First; 352 | while not D.Eof do 353 | begin 354 | if StopOn(D) then Break; 355 | D.Next; 356 | end; 357 | end; 358 | end; 359 | 360 | class function TSeq.Range(const aStart, aFinish: Integer): TSeq; 361 | begin 362 | Result.FFunc := Identity; 363 | Result.FIterate := 364 | procedure (const StopOn: TPredicate) 365 | var 366 | Item: Integer; 367 | begin 368 | for Item := aStart to aFinish do 369 | if StopOn(Item) then Break; 370 | end; 371 | end; 372 | 373 | end. 374 | -------------------------------------------------------------------------------- /demo/fmMain.pas: -------------------------------------------------------------------------------- 1 | unit fmMain; 2 | 3 | interface 4 | 5 | uses 6 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 7 | Dialogs, StdCtrls, Vcl.Grids, Vcl.DBGrids, Data.DB, Datasnap.DBClient, 8 | Vcl.ComCtrls, Vcl.ExtCtrls, Vcl.ActnList; 9 | 10 | type 11 | TFrmDemo = class(TForm) 12 | ClientDataSet1: TClientDataSet; 13 | DataSource1: TDataSource; 14 | PageControl1: TPageControl; 15 | TabSheet1: TTabSheet; 16 | Button1: TButton; 17 | Button2: TButton; 18 | Button3: TButton; 19 | Button4: TButton; 20 | Button5: TButton; 21 | Panel1: TPanel; 22 | PageControl2: TPageControl; 23 | TabSheet3: TTabSheet; 24 | Memo1: TMemo; 25 | TabSheet4: TTabSheet; 26 | DBGrid1: TDBGrid; 27 | Button9: TButton; 28 | TabSheet5: TTabSheet; 29 | Button10: TButton; 30 | btnDsLoop: TButton; 31 | atlDemo: TActionList; 32 | actDemo01: TAction; 33 | actDemo02: TAction; 34 | actDemo03A: TAction; 35 | actDemo03B: TAction; 36 | actDemo04: TAction; 37 | actDemo05: TAction; 38 | actDemo06: TAction; 39 | Button6: TButton; 40 | actDemo07: TAction; 41 | Button7: TButton; 42 | actDemo08: TAction; 43 | Button8: TButton; 44 | Button11: TButton; 45 | actDemo09: TAction; 46 | btnContinue: TButton; 47 | procedure Button5Click(Sender: TObject); 48 | procedure btnDsLoopClick(Sender: TObject); 49 | procedure FormCreate(Sender: TObject); 50 | procedure actDemo01Execute(Sender: TObject); 51 | procedure actDemo02Execute(Sender: TObject); 52 | procedure actDemo03AExecute(Sender: TObject); 53 | procedure actDemo03BExecute(Sender: TObject); 54 | procedure actDemo04Execute(Sender: TObject); 55 | procedure actDemo05Execute(Sender: TObject); 56 | procedure actDemo06Execute(Sender: TObject); 57 | procedure actDemo07Execute(Sender: TObject); 58 | procedure actDemo08Execute(Sender: TObject); 59 | procedure actDemo09Execute(Sender: TObject); 60 | procedure btnContinueClick(Sender: TObject); 61 | private 62 | FCanContinue: Boolean; 63 | procedure Pause; 64 | procedure PrintNum(X: Integer); 65 | procedure PrintStr(S: string; const aPause: Boolean = True); overload; 66 | procedure PrintStr(const aFormatStr: string; const Args: array of const; const aPause: Boolean = True); overload; 67 | procedure PrintString(S: string); 68 | procedure PrintTitle(S: string); 69 | procedure PrintHeader(S: string); 70 | procedure PrintDone; 71 | end; 72 | 73 | TEmpDetail = record 74 | Name: string; 75 | Salary: Double; 76 | YearsOfService: Integer; 77 | end; 78 | 79 | var 80 | FrmDemo: TFrmDemo; 81 | 82 | implementation 83 | 84 | {$R *.dfm} 85 | 86 | uses 87 | Math, 88 | DateUtils, 89 | StrUtils, 90 | Generics.Collections, 91 | Functional.Sequence, 92 | Functional.FuncFactory; 93 | 94 | var 95 | IntArray_1to10: TArray; 96 | 97 | { TFrmDemo } 98 | 99 | procedure TFrmDemo.FormCreate(Sender: TObject); 100 | begin 101 | FCanContinue := True; 102 | ClientDataSet1.FileName := 'data\employee.cds'; 103 | ClientDataSet1.Open; 104 | 105 | IntArray_1to10 := TArray.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 106 | end; 107 | 108 | procedure TFrmDemo.actDemo01Execute(Sender: TObject); 109 | begin 110 | PrintTitle('Demo 1. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 111 | PrintHeader('ForEach PrintNum'); 112 | 113 | TSeq 114 | .From(IntArray_1to10) 115 | .ForEach(PrintNum); 116 | 117 | PrintDone; 118 | end; 119 | 120 | function IsEven(const I: Integer): Boolean; 121 | begin 122 | Result := I mod 2 = 0; 123 | end; 124 | 125 | procedure TFrmDemo.actDemo02Execute(Sender: TObject); 126 | begin 127 | PrintTitle('Demo 2. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 128 | PrintHeader('Where (IsEven) example'); 129 | 130 | TSeq.From(IntArray_1to10) 131 | .Where(IsEven) 132 | .ForEach(PrintNum); 133 | 134 | PrintDone; 135 | end; 136 | 137 | procedure TFrmDemo.actDemo03AExecute(Sender: TObject); 138 | var 139 | Seq: TSeq; 140 | begin 141 | PrintTitle('Demo 3A. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 142 | 143 | Seq := TSeq.From(IntArray_1to10); 144 | 145 | PrintHeader('Select (add 12) returning an integer'); 146 | Seq 147 | .Select( 148 | function(I: Integer): Integer 149 | begin 150 | Result := I + 12; 151 | end) 152 | .ForEach(PrintNum); 153 | 154 | PrintHeader('Select (add 12) returning a string)'); 155 | Seq 156 | .Select( 157 | function(I: Integer): string 158 | begin 159 | Result := Format('Calculation: %d + 12 = %d', [I, I + 12]); 160 | end) 161 | .ForEach(PrintString); 162 | 163 | PrintDone; 164 | end; 165 | 166 | function Add12(I: Integer): Integer; 167 | begin 168 | Result := I + 12; 169 | end; 170 | 171 | function Add12String(I: Integer): string; 172 | begin 173 | Result := Format('Calculation: %d + 12 = %d', [I, Add12(I)]); 174 | end; 175 | 176 | procedure TFrmDemo.actDemo03BExecute(Sender: TObject); 177 | var 178 | Seq: TSeq; 179 | begin 180 | PrintTitle('Demo 3B. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 181 | 182 | Seq := TSeq.From(IntArray_1to10); 183 | 184 | PrintHeader('Select (add 12) - returning an integer'); 185 | Seq 186 | .Map(Add12) 187 | .ForEach(PrintNum); 188 | 189 | PrintHeader('Select (add 12) returning a string'); 190 | Seq 191 | .Select(Add12String) 192 | .ForEach(PrintString); 193 | 194 | PrintDone; 195 | end; 196 | 197 | procedure TFrmDemo.actDemo04Execute(Sender: TObject); 198 | var 199 | Seq: TSeq; 200 | begin 201 | PrintTitle('Demo 4. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 202 | 203 | Seq := TSeq.From(IntArray_1to10); 204 | 205 | PrintHeader('Take the first 5 items'); 206 | Seq 207 | .Take(5) 208 | .ForEach(PrintNum); 209 | 210 | PrintHeader('Skip the first 6 items'); 211 | Seq 212 | .Skip(6) 213 | .ForEach(PrintNum); 214 | 215 | PrintHeader('Skip the first 3 items and Take the next 6 items'); 216 | Seq 217 | .Skip(3) 218 | .Take(6) 219 | .ForEach(PrintNum); 220 | 221 | PrintDone; 222 | end; 223 | 224 | procedure TFrmDemo.actDemo05Execute(Sender: TObject); 225 | var 226 | Seq: TSeq; 227 | begin 228 | PrintTitle('Demo 5. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 229 | 230 | Seq := TSeq.From(IntArray_1to10); 231 | 232 | PrintHeader('TakeWhile value of item < 7'); 233 | Seq 234 | .TakeWhile(function(const Item: Integer): Boolean begin Result := Item < 7 end) 235 | .ForEach(PrintNum); 236 | 237 | PrintHeader('Skip first 2 items then TakeWhile item value < 9'); 238 | Seq 239 | .Skip(2) 240 | .TakeWhile(function(const Item: Integer): Boolean begin Result := Item < 9 end) 241 | .ForEach(PrintNum); 242 | 243 | PrintDone; 244 | end; 245 | 246 | procedure TFrmDemo.actDemo06Execute(Sender: TObject); 247 | var 248 | Seq: TSeq; 249 | LessThan: TFunc>; 250 | begin 251 | PrintTitle('Demo 6. Array of Integer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]'); 252 | 253 | Seq := TSeq.From(IntArray_1to10); 254 | 255 | PrintHeader('SkipWhile value of item <= 3'); 256 | Seq 257 | .SkipWhile(function (const Item: Integer): Boolean begin Result := Item <= 3 end) 258 | .ForEach(PrintNum); 259 | 260 | PrintHeader('SkipWhile item value < 5 then Take the next 3 items'); 261 | Seq 262 | .SkipWhile(function (const Item: Integer): Boolean begin Result := Item < 5 end) 263 | .Take(3) 264 | .ForEach(PrintNum); 265 | 266 | // LessThan is an anonymous function that returns another anonymous function! 267 | LessThan := 268 | function (Num: Integer): TPredicate 269 | begin 270 | Result := 271 | function(const I: Integer): Boolean 272 | begin 273 | Result := I < Num; 274 | end; 275 | end; 276 | 277 | PrintHeader('SkipWhile item value < 2 then TakeWhile item value < 9'); 278 | Seq 279 | .SkipWhile(LessThan(2)) 280 | .TakeWhile(LessThan(9)) 281 | .ForEach(PrintNum); 282 | 283 | PrintDone; 284 | end; 285 | 286 | procedure TFrmDemo.actDemo07Execute(Sender: TObject); 287 | var 288 | Numbers: TArray; 289 | SumInts: TFoldFunc; 290 | Total: Integer; 291 | CommaSeparate: TFoldFunc; 292 | CsvRec: string; 293 | begin 294 | PrintTitle('Demo 7. Array of Integer = [1, 5, 5, 9, 23, 4, 10]'); 295 | 296 | Numbers := TArray.Create(1, 5, 5, 9, 23, 4, 10); 297 | 298 | PrintHeader('Items in the array'); 299 | TSeq.From(Numbers) 300 | .ForEach(PrintNum); 301 | 302 | PrintHeader('Fold example - Sum items in an array.'); 303 | SumInts := 304 | function(const I: Integer; const Accumulator: Integer): Integer 305 | begin 306 | Result := Accumulator + I; 307 | end; 308 | 309 | Total := TSeq 310 | .From(Numbers) 311 | .Fold(SumInts, 0); 312 | 313 | PrintStr('Total = %d', [Total]); 314 | 315 | PrintHeader('Fold example - Append items into a comma-separated string.'); 316 | 317 | CommaSeparate := 318 | function(const I: Integer; const Accumulator: string): string 319 | begin 320 | Result := Accumulator + IfThen(Accumulator = '', '', ',') + IntToStr(I) 321 | end; 322 | 323 | CsvRec := TSeq 324 | .From(Numbers) 325 | .Fold(CommaSeparate, ''); 326 | 327 | PrintStr(CsvRec); 328 | 329 | PrintDone; 330 | end; 331 | 332 | procedure TFrmDemo.actDemo08Execute(Sender: TObject); 333 | const 334 | ALPHA_CHARS = ['a'..'z', 'A'..'Z']; 335 | VOWELS = ['a','e','i','o','u','A','E','I','O','U']; 336 | var 337 | S: string; 338 | PrintChar: TProc; 339 | begin 340 | S := 'Hello, World!'; 341 | 342 | PrintChar := 343 | procedure (C: Char) 344 | begin 345 | PrintStr('The character = ''%s''', [C]) 346 | end; 347 | 348 | PrintTitle(Format('Demo 8. string = ''%s''', [S])); 349 | 350 | PrintHeader('ForEach over a string value'); 351 | TSeq.From(S) 352 | .ForEach(PrintChar); 353 | 354 | PrintHeader('Filter for vowels only'); 355 | TSeq.From(S) 356 | .Filter(function (const C: Char): Boolean begin Result := CharInSet(C, VOWELS); end) 357 | .ForEach(PrintChar); 358 | 359 | PrintHeader('Filter for consonants and captalise'); 360 | TSeq.From(S) 361 | .Filter(function (const C: Char): Boolean begin Result := CharInSet(C, ALPHA_CHARS) and not CharInSet(C, VOWELS); end) 362 | .Map(function (C: Char): Char begin Result := UpCase(C) end) 363 | .ForEach(PrintChar); 364 | 365 | PrintDone; 366 | end; 367 | 368 | procedure TFrmDemo.actDemo09Execute(Sender: TObject); 369 | var 370 | Animals: TStringList; 371 | begin 372 | Animals := TStringList.Create; 373 | try 374 | PrintTitle('Demo 9. A list of animals in a TStringList'); 375 | Animals.CommaText := 376 | 'cat,dog,mouse,horse,cockatoo,pig,bear,goat,cow,' + 377 | 'sheep,cobra,rabbit,crab,lion,tiger,cougar,snake'; 378 | 379 | PrintHeader('ForEach over a TStrings object'); 380 | TSeq.From(Animals) 381 | .ForEach(PrintString); 382 | 383 | PrintHeader('Filter for strings starting with ''c'''); 384 | TSeq.From(Animals) 385 | .Filter(function (const S: string): Boolean 386 | begin 387 | Result := Copy(S, 1, 1) = 'c' 388 | end) 389 | .ForEach(PrintString); 390 | 391 | finally 392 | Animals.Free; 393 | end; 394 | 395 | PrintDone; 396 | end; 397 | 398 | procedure TFrmDemo.btnContinueClick(Sender: TObject); 399 | begin 400 | FCanContinue := True; 401 | end; 402 | 403 | function BySalary(const D: TDataSet): Boolean; 404 | begin 405 | Result := D.FieldByName('Salary').AsCurrency < 25000 406 | end; 407 | 408 | function ToEmpRecord(D: TDataSet): TEmpDetail; 409 | begin 410 | Result.Name := D.FieldByName('FirstName').AsString + ' ' + D.FieldByName('LastName').AsString; 411 | Result.Salary := D.FieldByName('Salary').AsFloat; 412 | Result.YearsOfService := YearsBetween(Now, D.FieldByName('HireDate').AsDateTime); 413 | end; 414 | 415 | procedure TFrmDemo.btnDsLoopClick(Sender: TObject); 416 | var 417 | EmpList: TList; 418 | Detail: TEmpDetail; 419 | 420 | begin 421 | EmpList := TSeq.From(ClientDataSet1) 422 | .Filter(BySalary) 423 | .Map(ToEmpRecord) 424 | .ToList; 425 | 426 | // EmpList := TList.Create; 427 | // try 428 | // ClientDataSet1.First; 429 | // while not ClientDataSet1.Eof do 430 | // begin 431 | // if ClientDataSet1.FieldByName('Salary').AsCurrency < 25000 then 432 | // begin 433 | // Detail.Name := ClientDataSet1.FieldByName('FirstName').AsString + ' ' + ClientDataSet1.FieldByName('LastName').AsString; 434 | // Detail.Salary := ClientDataSet1.FieldByName('Salary').AsFloat; 435 | // Detail.YearsOfService := YearsBetween(Now, ClientDataSet1.FieldByName('HireDate').AsDateTime); 436 | // EmpList.Add(Detail); 437 | // end; 438 | // ClientDataSet1.Next; 439 | // end; 440 | // 441 | try 442 | for Detail in EmpList do 443 | PrintStr('%s - %m (%d years of service)', [Detail.Name, Detail.Salary, Detail.YearsOfService]); 444 | 445 | finally 446 | EmpList.Free; 447 | end; 448 | 449 | end; 450 | 451 | procedure TFrmDemo.Button5Click(Sender: TObject); 452 | type 453 | TEmpSummary = record 454 | Count: Integer; 455 | Sum: Double; 456 | end; 457 | 458 | const 459 | ZERO_VAL: TEmpSummary = (Count: 0; Sum: 0); 460 | 461 | var 462 | EmpDS: TSeq; 463 | Total: TEmpSummary; 464 | S: TList; 465 | Item: string; 466 | 467 | begin 468 | EmpDS := TSeq.From(ClientDataSet1) 469 | .Filter(function (const D: TDataSet): Boolean begin Result := D.FieldByName('Salary').AsCurrency < 20000 end); 470 | 471 | EmpDS 472 | .ForEach( procedure(D: TDataSet) 473 | var 474 | YearsOfService: Integer; 475 | begin 476 | YearsOfService := YearsBetween(Now, D.FieldByName('HireDate').AsDateTime); 477 | PrintStr('%s %s - %m (%d years of service)', 478 | [D.FieldByName('FirstName').AsString, D.FieldByName('LastName').AsString, 479 | D.FieldByName('Salary').AsFloat, YearsOfService]) 480 | end); 481 | Memo1.Lines.Add('-----------------'); 482 | 483 | Total := EmpDS.Fold( 484 | function(const D: TDataSet; const Acc: TEmpSummary): TEmpSummary 485 | begin 486 | Result.Count := Acc.Count + 1; 487 | Result.Sum := Acc.Sum + D.FieldByName('Salary').AsFloat; 488 | end, ZERO_VAL); 489 | Memo1.Lines.Add(Format('Count=%d, Sum=%m, Avg=%f', [Total.Count, Total.Sum, Total.Sum/Total.Count])); 490 | Memo1.Lines.Add('-----------------'); 491 | 492 | S := EmpDS 493 | .Map(function (D: TDataSet): string 494 | begin 495 | Result := D.FieldByName('LastName').AsString + ', ' + 496 | D.FieldByName('FirstName').AsString; 497 | end) 498 | .ToList; 499 | try 500 | S.Sort; 501 | for Item in S do 502 | Memo1.Lines.Add(Item); 503 | finally 504 | S.Free; 505 | end; 506 | 507 | end; 508 | 509 | procedure TFrmDemo.PrintString(S: string); 510 | begin 511 | PrintStr(S); 512 | end; 513 | procedure TFrmDemo.PrintStr(S: string; const aPause: Boolean = True); 514 | begin 515 | if aPause then 516 | Sleep(300); 517 | Memo1.Lines.Add(S); 518 | end; 519 | 520 | procedure TFrmDemo.PrintStr(const aFormatStr: string; const Args: array of const; const aPause: Boolean); 521 | begin 522 | PrintStr(Format(aFormatStr, Args), aPause); 523 | end; 524 | 525 | procedure TFrmDemo.PrintNum(X: Integer); 526 | begin 527 | PrintStr(IntToStr(X)); 528 | end; 529 | 530 | procedure TFrmDemo.PrintTitle(S: string); 531 | begin 532 | Memo1.Clear; 533 | Application.ProcessMessages; 534 | PrintStr(S, False); 535 | PrintStr(StringOfChar('=', Max(39, Length(S)) + 1), False); 536 | end; 537 | 538 | procedure TFrmDemo.PrintHeader(S: string); 539 | begin 540 | PrintStr('', False); 541 | PrintStr(StringOfChar('-', Length(S) + 1), False); 542 | PrintStr(S, False); 543 | PrintStr(StringOfChar('-', Length(S) + 1), False); 544 | Pause; 545 | end; 546 | 547 | procedure TFrmDemo.Pause; 548 | begin 549 | btnContinue.SetFocus; 550 | FCanContinue := False; 551 | while not FCanContinue do 552 | Application.ProcessMessages; 553 | end; 554 | 555 | procedure TFrmDemo.PrintDone; 556 | begin 557 | PrintStr('', False); 558 | PrintStr(StringOfChar('=', 40), False); 559 | PrintStr('Done!', False); 560 | end; 561 | 562 | end. 563 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------