├── .config └── dotnet-tools.json ├── .editorconfig ├── .github └── workflows │ ├── dotnet.yml │ └── github-pages.yml ├── .gitignore ├── FSharp.Collections.Builders.sln ├── FSharp.Collections.Builders ├── CollectionBuilders.fs └── FSharp.Collections.Builders.fsproj ├── LICENSE.md ├── NuGet.Config ├── README.md ├── docs ├── content │ └── fsdocs-theme.css └── img │ ├── favicon.ico │ └── logo.png └── logo.png /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "fsdocs-tool": { 6 | "version": "21.0.0-beta-002", 7 | "commands": [ 8 | "fsdocs" 9 | ], 10 | "rollForward": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # To learn more about .editorconfig see https://aka.ms/editorconfigdocs 2 | 3 | [*] 4 | indent_style = space 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [*.{xml,yml,fsproj}] 10 | indent_size = 2 11 | 12 | [*.{fs,fsx}] 13 | indent_size = 4 14 | fsharp_space_before_uppercase_invocation=true 15 | fsharp_space_before_lowercase_invocation=true 16 | fsharp_space_before_class_constructor=true 17 | fsharp_space_before_member=true 18 | fsharp_space_before_colon=true 19 | fsharp_space_before_parameter=true 20 | fsharp_maximum_line_length=200 21 | fsharp_maximum_function_binding_width=200 22 | fsharp_multiline_block_brackets_on_same_column=false 23 | fsharp_newline_between_type_definition_and_members=true 24 | fsharp_keep_if_then_in_same_line=true 25 | fsharp_align_function_signature_to_indentation=true 26 | fsharp_alternative_long_member_definitions=true 27 | fsharp_disable_elmish_syntax=true 28 | fsharp_multi_line_lambda_closing_newline=false 29 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up .NET 15 | uses: actions/setup-dotnet@v4 16 | with: 17 | dotnet-version: 8.x 18 | - name: Restore dependencies 19 | run: dotnet restore 20 | - name: Build 21 | run: dotnet build --no-restore -c Release 22 | - name: Test 23 | run: dotnet test --verbosity normal 24 | 25 | deploy: 26 | 27 | needs: build 28 | 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - uses: actions/checkout@v4 33 | - name: Set up .NET 34 | uses: actions/setup-dotnet@v4 35 | with: 36 | dotnet-version: 8.x 37 | env: 38 | NUGET_AUTH_TOKEN: ${{ secrets.NUGET_API_KEY }} 39 | - name: Pack 40 | run: | 41 | dotnet restore 42 | dotnet build -c Release 43 | dotnet pack ./FSharp.Collections.Builders/FSharp.Collections.Builders.fsproj -c Release --include-symbols 44 | - name: Publish 45 | run: dotnet nuget push ./FSharp.Collections.Builders/bin/Release/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate 46 | -------------------------------------------------------------------------------- /.github/workflows/github-pages.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | 7 | permissions: 8 | contents: read 9 | pages: write 10 | id-token: write 11 | 12 | concurrency: 13 | group: "pages" 14 | cancel-in-progress: false 15 | 16 | jobs: 17 | build-docs: 18 | 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up .NET 24 | uses: actions/setup-dotnet@v4 25 | with: 26 | dotnet-version: 8.x 27 | - name: Set up GitHub Pages 28 | uses: actions/configure-pages@v5 29 | - name: Restore dotnet tools 30 | run: dotnet tool restore 31 | - name: Restore dotnet projects 32 | run: dotnet restore 33 | - name: Build 34 | run: dotnet build ./FSharp.Collections.Builders/FSharp.Collections.Builders.fsproj -c Release -f net8.0 35 | - name: Copy readme to docs folder 36 | run: cp README.md docs/index.md 37 | - name: Build docs 38 | run: | 39 | dotnet fsdocs build \ 40 | --output ./out \ 41 | --properties Configuration=Release TargetFramework=net8.0 \ 42 | --parameters \ 43 | fsdocs-license-link https://github.com/fsprojects/FSharp.Collections.Builders/blob/main/LICENSE.md \ 44 | fsdocs-release-notes-link https://github.com/fsprojects/FSharp.Collections.Builders/releases 45 | - name: Upload GitHub Pages artifact 46 | uses: actions/upload-pages-artifact@v3 47 | with: 48 | path: './out' 49 | 50 | publish-docs: 51 | 52 | needs: build-docs 53 | 54 | environment: 55 | name: github-pages 56 | url: ${{ steps.deployment.outputs.page_url }} 57 | 58 | runs-on: ubuntu-latest 59 | 60 | steps: 61 | - uses: actions/checkout@v4 62 | - name: Deploy to GitHub Pages 63 | id: deployment 64 | uses: actions/deploy-pages@v4 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | gnore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | 400 | # FSharp.Formatting/fsdocs 401 | output/ 402 | tmp/ 403 | .fsdocs/ 404 | -------------------------------------------------------------------------------- /FSharp.Collections.Builders.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.33711.374 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Collections.Builders", "FSharp.Collections.Builders\FSharp.Collections.Builders.fsproj", "{5D160B65-DD73-48A7-88DB-9184C6DE971F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5D160B65-DD73-48A7-88DB-9184C6DE971F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {5D160B65-DD73-48A7-88DB-9184C6DE971F}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {5D160B65-DD73-48A7-88DB-9184C6DE971F}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {5D160B65-DD73-48A7-88DB-9184C6DE971F}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {2BEF3132-1F57-48A1-8DE9-3BF63F7E80AB} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /FSharp.Collections.Builders/CollectionBuilders.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Collections.Builders 2 | 3 | open System 4 | open System.Collections.Generic 5 | open System.Collections.Immutable 6 | 7 | #nowarn "77" // set_Item. 8 | 9 | /// 10 | /// 11 | /// Contains computation expression builders for conveniently and efficiently constructing common collections. 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// Contains computation expression builders for common collection types. 17 | /// 18 | /// See also: 19 | /// , 20 | /// . 21 | /// 22 | /// 23 | [] 24 | module Core = 25 | /// A special compiler-recognized delegate for specifying blocks of code with access to the collection builder state. 26 | [] 27 | type CollectionBuilderCode<'T> = delegate of byref<'T> -> unit 28 | 29 | /// Contains methods to build collections using computation expression syntax. 30 | type CollectionBuilderBase () = 31 | member inline _.Combine ([] f1 : CollectionBuilderCode<_>, [] f2 : CollectionBuilderCode<_>) = 32 | CollectionBuilderCode (fun sm -> f1.Invoke &sm; f2.Invoke &sm) 33 | 34 | member inline _.Delay ([] f : unit -> CollectionBuilderCode<_>) = 35 | CollectionBuilderCode (fun sm -> (f ()).Invoke &sm) 36 | 37 | member inline _.Zero () = CollectionBuilderCode (fun _ -> ()) 38 | 39 | member inline _.While ([] condition : unit -> bool, [] body : CollectionBuilderCode<_>) = 40 | CollectionBuilderCode (fun sm -> 41 | while condition () do 42 | body.Invoke &sm) 43 | 44 | member inline _.TryWith ([] body : CollectionBuilderCode<_>, [] handle : exn -> CollectionBuilderCode<_>) = 45 | CollectionBuilderCode (fun sm -> 46 | try body.Invoke &sm 47 | with e -> (handle e).Invoke &sm) 48 | 49 | member inline _.TryFinally ([] body : CollectionBuilderCode<_>, compensation : unit -> unit) = 50 | CollectionBuilderCode (fun sm -> 51 | try body.Invoke &sm 52 | with _ -> 53 | compensation () 54 | reraise () 55 | compensation ()) 56 | 57 | member inline builder.Using (disposable : #IDisposable, [] body : #IDisposable -> CollectionBuilderCode<_>) = 58 | builder.TryFinally ((fun sm -> (body disposable).Invoke &sm), (fun () -> if not (isNull (box disposable)) then disposable.Dispose ())) 59 | 60 | /// The base collection builder. 61 | type CollectionBuilder () = 62 | inherit CollectionBuilderBase () 63 | member inline _.Yield x = CollectionBuilderCode (fun sm -> ignore (^a : (member Add : ^b -> _) (sm, x))) 64 | 65 | /// The base dictionary builder. 66 | type DictionaryBuilder () = 67 | inherit CollectionBuilderBase () 68 | member inline _.Yield (k, v) = CollectionBuilderCode (fun sm -> ignore (^a : (member set_Item : ^b * ^c -> _) (sm, k, v))) 69 | 70 | [] 71 | type ResizeArrayBuilder<'T> () = 72 | inherit CollectionBuilder () 73 | static member val Instance = ResizeArrayBuilder<'T> () 74 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 75 | let mutable sm = ResizeArray<'T> () 76 | f.Invoke &sm 77 | sm 78 | 79 | [] 80 | type HashSetBuilder<'T> () = 81 | inherit CollectionBuilder () 82 | static member val Instance = HashSetBuilder<'T> () 83 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 84 | let mutable sm = HashSet<'T> () 85 | f.Invoke &sm 86 | sm 87 | 88 | [] 89 | type SortedSetBuilder<'T> () = 90 | inherit CollectionBuilder () 91 | static member val Instance = SortedSetBuilder<'T> () 92 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 93 | let mutable sm = SortedSet<'T> () 94 | f.Invoke &sm 95 | sm 96 | 97 | [] 98 | type GenericCollectionBuilder<'Collection when 'Collection : (new : unit -> 'Collection)> () = 99 | inherit CollectionBuilder () 100 | static member val Instance = GenericCollectionBuilder<'Collection> () 101 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 102 | let mutable sm = new 'Collection () 103 | f.Invoke &sm 104 | sm 105 | 106 | /// 107 | [] 108 | type DictionaryBuilder<'Key, 'Value when 'Key : equality> () = 109 | inherit DictionaryBuilder () 110 | static member val Instance = DictionaryBuilder<'Key, 'Value> () 111 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 112 | let mutable sm = Dictionary<'Key, 'Value> () 113 | f.Invoke &sm 114 | sm 115 | 116 | [] 117 | type SortedDictionaryBuilder<'Key, 'Value when 'Key : equality> () = 118 | inherit DictionaryBuilder () 119 | static member val Instance = SortedDictionaryBuilder<'Key, 'Value> () 120 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 121 | let mutable sm = SortedDictionary<'Key, 'Value> () 122 | f.Invoke &sm 123 | sm 124 | 125 | [] 126 | type GenericDictionaryBuilder<'Dictionary when 'Dictionary : (new : unit -> 'Dictionary)> () = 127 | inherit DictionaryBuilder () 128 | static member val Instance = GenericDictionaryBuilder<'Dictionary> () 129 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 130 | let mutable sm = new 'Dictionary () 131 | f.Invoke &sm 132 | sm 133 | 134 | [] 135 | type SetBuilder<'T when 'T : comparison> () = 136 | inherit CollectionBuilderBase () 137 | static member val Instance = SetBuilder<'T> () 138 | member inline _.Yield x = CollectionBuilderCode (fun sm -> sm <- Set.add x sm) 139 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 140 | let mutable sm = Set.empty<'T> 141 | f.Invoke &sm 142 | sm 143 | 144 | [] 145 | type MapBuilder<'Key, 'Value when 'Key : comparison> () = 146 | inherit CollectionBuilderBase () 147 | static member val Instance = MapBuilder<'Key, 'Value> () 148 | member inline _.Yield (k, v) = CollectionBuilderCode (fun sm -> sm <- Map.add k v sm) 149 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 150 | let mutable sm = Map.empty<'Key, 'Value> 151 | f.Invoke &sm 152 | sm 153 | 154 | [] 155 | type ImmutableArrayBuilder<'T> () = 156 | inherit CollectionBuilder () 157 | static member val Instance = ImmutableArrayBuilder<'T> () 158 | member inline _.Run ([] f : CollectionBuilderCode.Builder>) = 159 | let mutable sm = ImmutableArray.CreateBuilder () 160 | f.Invoke &sm 161 | sm.ToImmutable () 162 | 163 | [] 164 | type ImmutableHashSetBuilder<'T> () = 165 | inherit CollectionBuilder () 166 | static member val Instance = ImmutableHashSetBuilder<'T> () 167 | member inline _.Run ([] f : CollectionBuilderCode.Builder>) = 168 | let mutable sm = ImmutableHashSet.CreateBuilder () 169 | f.Invoke &sm 170 | sm.ToImmutable () 171 | 172 | [] 173 | type ImmutableSortedSetBuilder<'T> () = 174 | inherit CollectionBuilder () 175 | static member val Instance = ImmutableSortedSetBuilder<'T> () 176 | member inline _.Run ([] f : CollectionBuilderCode.Builder>) = 177 | let mutable sm = ImmutableSortedSet.CreateBuilder () 178 | f.Invoke &sm 179 | sm.ToImmutable () 180 | 181 | [] 182 | type ImmutableListBuilder<'T> () = 183 | inherit CollectionBuilder () 184 | static member val Instance = ImmutableListBuilder<'T> () 185 | member inline _.Run ([] f : CollectionBuilderCode.Builder>) = 186 | let mutable sm = ImmutableList.CreateBuilder () 187 | f.Invoke &sm 188 | sm.ToImmutable () 189 | 190 | [] 191 | type ImmutableDictionaryBuilder<'Key, 'Value> () = 192 | inherit DictionaryBuilder () 193 | static member val Instance = ImmutableDictionaryBuilder<'Key, 'Value> () 194 | member inline _.Run ([] f : CollectionBuilderCode.Builder>) = 195 | let mutable sm = ImmutableDictionary.CreateBuilder () 196 | f.Invoke &sm 197 | sm.ToImmutable () 198 | 199 | [] 200 | type ImmutableSortedDictionaryBuilder<'Key, 'Value> () = 201 | inherit DictionaryBuilder () 202 | static member val Instance = ImmutableSortedDictionaryBuilder<'Key, 'Value> () 203 | member inline _.Run ([] f : CollectionBuilderCode.Builder>) = 204 | let mutable sm = ImmutableSortedDictionary.CreateBuilder () 205 | f.Invoke &sm 206 | sm.ToImmutable () 207 | 208 | [] 209 | type SumBuilder () = 210 | inherit CollectionBuilderBase () 211 | member inline _.Yield x = CollectionBuilderCode (fun sm -> sm <- sm + x) 212 | member inline _.Run ([] f : CollectionBuilderCode<_>) = 213 | let mutable sm = LanguagePrimitives.GenericZero 214 | f.Invoke &sm 215 | sm 216 | 217 | /// 218 | /// Contains specialized overloads of for and yield! that give increased iteration performance 219 | /// for common collection types at the cost of requiring that the type of the collection being iterated be statically known. 220 | /// 221 | /// 222 | /// The type of xs must be annotated or otherwise known, 223 | /// but once it is, the appropriate specialized iteration technique 224 | /// will be used. 225 | /// 226 | /// let f (xs : int list) = 227 | /// resizeArray { 228 | /// for x in xs -> x * x 229 | /// } 230 | /// 231 | /// xs is known to be a list because of the call to List.length. 232 | /// 233 | /// let g xs = 234 | /// let len = List.length xs 235 | /// resizeArray { 236 | /// for x in xs -> x * len 237 | /// } 238 | /// 239 | /// 240 | module Specialized = 241 | /// 242 | /// Augments with 243 | /// specialized for implementations. 244 | /// 245 | type CollectionBuilderBase with 246 | member inline builder.For (sequence : seq<_>, [] body : _ -> CollectionBuilderCode<_>) = 247 | builder.Using (sequence.GetEnumerator (), fun e -> builder.While ((fun () -> e.MoveNext ()), (fun sm -> (body e.Current).Invoke &sm))) 248 | 249 | member inline _.For (list : _ list, [] body : _ -> CollectionBuilderCode<_>) = 250 | CollectionBuilderCode (fun sm -> 251 | for x in list do 252 | (body x).Invoke &sm) 253 | 254 | member inline _.For (array : _ array, [] body : _ -> CollectionBuilderCode<_>) = 255 | CollectionBuilderCode (fun sm -> 256 | for x in array do 257 | (body x).Invoke &sm) 258 | 259 | member inline _.For (set : Set<_>, [] body : _ -> CollectionBuilderCode<_>) = 260 | CollectionBuilderCode (fun sm -> 261 | let mutable sm' = sm 262 | set |> Set.iter (fun x -> (body x).Invoke &sm') 263 | sm <- sm') 264 | 265 | member inline _.For (map : Map<_, _>, [] body : _ -> CollectionBuilderCode<_>) = 266 | CollectionBuilderCode (fun sm -> 267 | let mutable sm' = sm 268 | map |> Map.iter (fun k v -> (body (k, v)).Invoke &sm') 269 | sm <- sm') 270 | 271 | member inline _.For (resizeArray : ResizeArray<_>, [] body : _ -> CollectionBuilderCode<_>) = 272 | CollectionBuilderCode (fun sm -> 273 | for i in 0 .. resizeArray.Count - 1 do 274 | (body resizeArray[i]).Invoke &sm) 275 | 276 | member inline _.For (immutableArray : ImmutableArray<_>, [] body : _ -> CollectionBuilderCode<_>) = 277 | CollectionBuilderCode (fun sm -> 278 | for i in 0 .. immutableArray.Length - 1 do 279 | (body immutableArray[i]).Invoke &sm) 280 | 281 | member inline _.For (immutableArrayBuilder : ImmutableArray<_>.Builder, [] body : _ -> CollectionBuilderCode<_>) = 282 | CollectionBuilderCode (fun sm -> 283 | for i in 0 .. immutableArrayBuilder.Count - 1 do 284 | (body immutableArrayBuilder[i]).Invoke &sm) 285 | 286 | /// 287 | /// Augments with 288 | /// specialized yield! implementations. 289 | /// 290 | type CollectionBuilder with 291 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun x -> builder.Yield x) 292 | member inline builder.YieldFrom (xs : _ list) = builder.For (xs, fun x -> builder.Yield x) 293 | member inline builder.YieldFrom (xs : _ array) = builder.For (xs, fun x -> builder.Yield x) 294 | member inline builder.YieldFrom (xs : ResizeArray<_>) = builder.For (xs, fun x -> builder.Yield x) 295 | member inline builder.YieldFrom (xs : Set<_>) = builder.For (xs, fun x -> builder.Yield x) 296 | member inline builder.YieldFrom (xs : Map<_, _>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 297 | member inline builder.YieldFrom (xs : ImmutableArray<_>) = builder.For (xs, fun x -> builder.Yield x) 298 | 299 | /// 300 | /// Augments with 301 | /// specialized yield! implementations. 302 | /// 303 | type DictionaryBuilder with 304 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 305 | member inline builder.YieldFrom (xs : _ list) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 306 | member inline builder.YieldFrom (xs : _ array) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 307 | member inline builder.YieldFrom (xs : ResizeArray<_>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 308 | member inline builder.YieldFrom (xs : Set<_>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 309 | member inline builder.YieldFrom (xs : Map<_, _>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 310 | member inline builder.YieldFrom (xs : ImmutableArray<_>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 311 | 312 | /// 313 | /// Augments with 314 | /// specialized for implementations. 315 | /// 316 | type SumBuilder with 317 | member inline _.For (span : Span<_>, [] body : _ -> CollectionBuilderCode<_>) = 318 | let mutable acc = LanguagePrimitives.GenericZero 319 | for x in span do 320 | (body x).Invoke &acc 321 | CollectionBuilderCode (fun sm -> sm <- sm + acc) 322 | 323 | member inline _.For (span : ReadOnlySpan<_>, [] body : _ -> CollectionBuilderCode<_>) = 324 | let mutable acc = LanguagePrimitives.GenericZero 325 | for x in span do 326 | (body x).Invoke &acc 327 | CollectionBuilderCode (fun sm -> sm <- sm + acc) 328 | 329 | /// 330 | /// Builds a using computation expression syntax. 331 | /// 332 | /// 333 | /// 334 | /// let f (xs : int list) = 335 | /// resizeArray { 336 | /// for x in xs -> x * x 337 | /// } 338 | /// 339 | /// 340 | /// let a = 1 341 | /// let xs = [|2..100|] 342 | /// let ys = resizeArray { 0; 1; yield! xs } 343 | /// 344 | /// 345 | let resizeArray<'T> = ResizeArrayBuilder<'T>.Instance 346 | 347 | /// 348 | /// Builds a using computation expression syntax. 349 | /// 350 | /// 351 | /// 352 | /// let xs = hashSet { 1; 2; 3 } 353 | /// 354 | /// 355 | let hashSet<'T> = HashSetBuilder<'T>.Instance 356 | 357 | /// 358 | /// Builds a using computation expression syntax. 359 | /// 360 | /// 361 | /// 362 | /// let xs = sortedSet { 1; 2; 3 } 363 | /// 364 | /// 365 | let sortedSet<'T> = SortedSetBuilder<'T>.Instance 366 | 367 | /// 368 | /// Builds a using computation expression syntax. 369 | /// 370 | /// 371 | /// 372 | /// let xs = set' { 1; 2; 3 } 373 | /// 374 | /// 375 | let set'<'T when 'T : comparison> = SetBuilder<'T>.Instance 376 | 377 | /// 378 | /// Builds a collection of the inferred or specified type using computation expression syntax. 379 | /// 380 | /// 381 | /// 382 | /// let xs = [|2..100|] 383 | /// let ys = collection<ResizeArray<int>> { 0; 1; yield! xs } 384 | /// let zs = collection<HashSet<int>> { 0; 1; yield! xs } 385 | /// 386 | /// 387 | /// let xs = [|2..100|] 388 | /// let ys : ResizeArray<int> = collection { 0; 1; yield! xs } 389 | /// let zs : HashSet<int> = collection { 0; 1; yield! xs } 390 | /// 391 | /// 392 | let collection<'Collection when 'Collection : (new : unit -> 'Collection)> = GenericCollectionBuilder<'Collection>.Instance 393 | 394 | /// 395 | /// Builds a using computation expression syntax. 396 | /// 397 | /// 398 | /// 399 | /// let m = dictionary { 1, "a"; 2, "b"; 3, "c" } 400 | /// 401 | /// 402 | let dictionary<'Key, 'Value when 'Key : equality> = DictionaryBuilder<'Key, 'Value>.Instance 403 | 404 | /// 405 | /// Builds a using computation expression syntax. 406 | /// 407 | /// 408 | /// 409 | /// let m = sortedDictionary { 1, "a"; 2, "b"; 3, "c" } 410 | /// 411 | /// 412 | let sortedDictionary<'Key, 'Value when 'Key : equality> = SortedDictionaryBuilder<'Key, 'Value>.Instance 413 | 414 | /// 415 | /// Builds a using computation expression syntax. 416 | /// 417 | /// 418 | /// 419 | /// let m = map { 1, "a"; 2, "b"; 3, "c" } 420 | /// 421 | /// 422 | let map<'Key, 'Value when 'Key : comparison> = MapBuilder<'Key, 'Value>.Instance 423 | 424 | /// 425 | /// Builds a dictionary of the inferred or specified type using computation expression syntax. 426 | /// 427 | /// 428 | /// 429 | /// let m = dict'<Dictionary<int, int>> { 0, 0; 1, 1 } 430 | /// let m = dict'<SortedDictionary<int, int>> { 0, 0; 1, 1 } 431 | /// 432 | /// 433 | /// let m : Dictionary<int, int> = dict' { 0, 0; 1, 1 } 434 | /// let m : SortedDictionary<int, int> = dict' { 0, 0; 1, 1 } 435 | /// 436 | /// 437 | let dict'<'Dictionary when 'Dictionary : (new : unit -> 'Dictionary)> = GenericDictionaryBuilder<'Dictionary>.Instance 438 | 439 | /// 440 | /// Builds an using computation expression syntax. 441 | /// 442 | /// 443 | /// 444 | /// let xs = immutableArray { 1; 2; 3 } 445 | /// 446 | /// 447 | let immutableArray<'T> = ImmutableArrayBuilder<'T>.Instance 448 | 449 | /// 450 | /// Builds an using computation expression syntax. 451 | /// 452 | /// 453 | /// 454 | /// let xs = immutableHashSet { 1; 2; 3 } 455 | /// 456 | /// 457 | let immutableHashSet<'T> = ImmutableHashSetBuilder<'T>.Instance 458 | 459 | /// 460 | /// Builds an using computation expression syntax. 461 | /// 462 | /// 463 | /// 464 | /// let xs = immutableSortedSet { 1; 2; 3 } 465 | /// 466 | /// 467 | let immutableSortedSet<'T> = ImmutableSortedSetBuilder<'T>.Instance 468 | 469 | /// 470 | /// Builds an using computation expression syntax. 471 | /// 472 | /// 473 | /// 474 | /// let xs = immutableList { 1; 2; 3 } 475 | /// 476 | /// 477 | let immutableList<'T> = ImmutableListBuilder<'T>.Instance 478 | 479 | /// 480 | /// Builds an using computation expression syntax. 481 | /// 482 | /// 483 | /// 484 | /// let m = immutableDictionary { 1, "a"; 2, "b"; 3, "c" } 485 | /// 486 | /// 487 | let immutableDictionary<'Key, 'Value> = ImmutableDictionaryBuilder<'Key, 'Value>.Instance 488 | 489 | /// 490 | /// Builds an using computation expression syntax. 491 | /// 492 | /// 493 | /// 494 | /// let m = immutableSortedDictionary { 1, "a"; 2, "b"; 3, "c" } 495 | /// 496 | /// 497 | let immutableSortedDictionary<'Key, 'Value> = ImmutableSortedDictionaryBuilder<'Key, 'Value>.Instance 498 | 499 | /// 500 | /// Computes a sum using computation expression syntax. 501 | /// 502 | /// 503 | /// 504 | /// let s = sum { 1; 2; 3 } 505 | /// 506 | /// 507 | /// let xs = [1..100] 508 | /// let s = sum { for x in xs -> x } 509 | /// 510 | /// 511 | /// let xs = [4..100] 512 | /// let s = sum { 1; 2; 3; yield! xs } 513 | /// 514 | /// 515 | let sum = SumBuilder () 516 | 517 | /// 518 | /// Computes a sum using computation expression syntax. 519 | /// 520 | /// 521 | /// 522 | /// let s = Σ { 1; 2; 3 } 523 | /// 524 | /// 525 | /// let xs = [1..100] 526 | /// let s = Σ { for x in xs -> x } 527 | /// 528 | /// 529 | /// let xs = [4..100] 530 | /// let s = Σ { 1; 2; 3; yield! xs } 531 | /// 532 | /// 533 | let Σ = sum 534 | 535 | /// 536 | /// Exposes type-inference-friendly collection builders. 537 | /// 538 | /// 539 | /// The type of xs is inferred to be seq<int>. 540 | /// 541 | /// let f xs = 542 | /// resizeArray { 543 | /// for x in xs -> x * x 544 | /// } 545 | /// 546 | /// 547 | [] 548 | module Default = 549 | /// 550 | /// Augments with 551 | /// for implementations for . 552 | /// 553 | type CollectionBuilderBase with 554 | member inline builder.For (sequence : seq<_>, [] body : _ -> CollectionBuilderCode<_>) = 555 | builder.Using (sequence.GetEnumerator (), fun e -> builder.While ((fun () -> e.MoveNext ()), (fun sm -> (body e.Current).Invoke &sm))) 556 | 557 | /// 558 | /// Augments with 559 | /// yield! implementations for . 560 | /// 561 | type CollectionBuilder with 562 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun x -> builder.Yield x) 563 | 564 | /// 565 | /// Augments with 566 | /// yield! implementations for . 567 | /// 568 | type DictionaryBuilder with 569 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 570 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun (KeyValue (k, v)) -> builder.Yield (k, v)) 571 | 572 | /// 573 | /// Augments with 574 | /// yield! implementations for . 575 | /// 576 | type SetBuilder<'T when 'T : comparison> with 577 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun x -> builder.Yield x) 578 | 579 | /// 580 | /// Augments with 581 | /// yield! implementations for . 582 | /// 583 | type MapBuilder<'Key, 'Value when 'Key : comparison> with 584 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun (k, v) -> builder.Yield (k, v)) 585 | member inline builder.YieldFrom (xs : seq<_>) = builder.For (xs, fun (KeyValue (k, v)) -> builder.Yield (k, v)) 586 | 587 | /// 588 | /// Builds a using computation expression syntax. 589 | /// 590 | /// 591 | /// 592 | /// let f xs = 593 | /// resizeArray { 594 | /// for x in xs -> x * x 595 | /// } 596 | /// 597 | /// 598 | /// let a = 1 599 | /// let xs = [|2..100|] 600 | /// let ys = resizeArray { 0; 1; yield! xs } 601 | /// 602 | /// 603 | let resizeArray<'T> = ResizeArrayBuilder<'T>.Instance 604 | 605 | /// 606 | /// Builds a using computation expression syntax. 607 | /// 608 | /// 609 | /// 610 | /// let xs = hashSet { 1; 2; 3 } 611 | /// 612 | /// 613 | let hashSet<'T> = HashSetBuilder<'T>.Instance 614 | 615 | /// 616 | /// Builds a using computation expression syntax. 617 | /// 618 | /// 619 | /// 620 | /// let xs = sortedSet { 1; 2; 3 } 621 | /// 622 | /// 623 | let sortedSet<'T> = SortedSetBuilder<'T>.Instance 624 | 625 | /// 626 | /// Builds a using computation expression syntax. 627 | /// 628 | /// 629 | /// 630 | /// let xs = set' { 1; 2; 3 } 631 | /// 632 | /// 633 | let set'<'T when 'T : comparison> = SetBuilder<'T>.Instance 634 | 635 | /// 636 | /// Builds a collection of the inferred or specified type using computation expression syntax. 637 | /// 638 | /// 639 | /// 640 | /// let xs = [|2..100|] 641 | /// let ys = collection<ResizeArray<int>> { 0; 1; yield! xs } 642 | /// let zs = collection<HashSet<int>> { 0; 1; yield! xs } 643 | /// 644 | /// 645 | /// let xs = [|2..100|] 646 | /// let ys : ResizeArray<int> = collection { 0; 1; yield! xs } 647 | /// let zs : HashSet<int> = collection { 0; 1; yield! xs } 648 | /// 649 | /// 650 | let collection<'Collection when 'Collection : (new : unit -> 'Collection)> = GenericCollectionBuilder<'Collection>.Instance 651 | 652 | /// 653 | /// Builds a using computation expression syntax. 654 | /// 655 | /// 656 | /// 657 | /// let m = dictionary { 1, "a"; 2, "b"; 3, "c" } 658 | /// 659 | /// 660 | let dictionary<'Key, 'Value when 'Key : equality> = DictionaryBuilder<'Key, 'Value>.Instance 661 | 662 | /// 663 | /// Builds a using computation expression syntax. 664 | /// 665 | /// 666 | /// 667 | /// let m = sortedDictionary { 1, "a"; 2, "b"; 3, "c" } 668 | /// 669 | /// 670 | let sortedDictionary<'Key, 'Value when 'Key : equality> = SortedDictionaryBuilder<'Key, 'Value>.Instance 671 | 672 | /// 673 | /// Builds a using computation expression syntax. 674 | /// 675 | /// 676 | /// 677 | /// let m = map { 1, "a"; 2, "b"; 3, "c" } 678 | /// 679 | /// 680 | let map<'Key, 'Value when 'Key : comparison> = MapBuilder<'Key, 'Value>.Instance 681 | 682 | /// 683 | /// Builds a dictionary of the inferred or specified type using computation expression syntax. 684 | /// 685 | /// 686 | /// 687 | /// let m = dict'<Dictionary<int, int>> { 0, 0; 1, 1 } 688 | /// let m = dict'<SortedDictionary<int, int>> { 0, 0; 1, 1 } 689 | /// 690 | /// 691 | /// let m : Dictionary<int, int> = dict' { 0, 0; 1, 1 } 692 | /// let m : SortedDictionary<int, int> = dict' { 0, 0; 1, 1 } 693 | /// 694 | /// 695 | let dict'<'Dictionary when 'Dictionary : (new : unit -> 'Dictionary)> = GenericDictionaryBuilder<'Dictionary>.Instance 696 | 697 | /// 698 | /// Builds an using computation expression syntax. 699 | /// 700 | /// 701 | /// 702 | /// let xs = immutableArray { 1; 2; 3 } 703 | /// 704 | /// 705 | let immutableArray<'T> = ImmutableArrayBuilder<'T>.Instance 706 | 707 | /// 708 | /// Builds an using computation expression syntax. 709 | /// 710 | /// 711 | /// 712 | /// let xs = immutableHashSet { 1; 2; 3 } 713 | /// 714 | /// 715 | let immutableHashSet<'T> = ImmutableHashSetBuilder<'T>.Instance 716 | 717 | /// 718 | /// Builds an using computation expression syntax. 719 | /// 720 | /// 721 | /// 722 | /// let xs = immutableSortedSet { 1; 2; 3 } 723 | /// 724 | /// 725 | let immutableSortedSet<'T> = ImmutableSortedSetBuilder<'T>.Instance 726 | 727 | /// 728 | /// Builds an using computation expression syntax. 729 | /// 730 | /// 731 | /// 732 | /// let xs = immutableList { 1; 2; 3 } 733 | /// 734 | /// 735 | let immutableList<'T> = ImmutableListBuilder<'T>.Instance 736 | 737 | /// 738 | /// Builds an using computation expression syntax. 739 | /// 740 | /// 741 | /// 742 | /// let m = immutableDictionary { 1, "a"; 2, "b"; 3, "c" } 743 | /// 744 | /// 745 | let immutableDictionary<'Key, 'Value> = ImmutableDictionaryBuilder<'Key, 'Value>.Instance 746 | 747 | /// 748 | /// Builds an using computation expression syntax. 749 | /// 750 | /// 751 | /// 752 | /// let m = immutableSortedDictionary { 1, "a"; 2, "b"; 3, "c" } 753 | /// 754 | /// 755 | let immutableSortedDictionary<'Key, 'Value> = ImmutableSortedDictionaryBuilder<'Key, 'Value>.Instance 756 | 757 | /// 758 | /// Computes a sum using computation expression syntax. 759 | /// 760 | /// 761 | /// 762 | /// let s = sum { 1; 2; 3 } 763 | /// 764 | /// 765 | /// let xs = [1..100] 766 | /// let s = sum { for x in xs -> x } 767 | /// 768 | /// 769 | /// let xs = [4..100] 770 | /// let s = sum { 1; 2; 3; yield! xs } 771 | /// 772 | /// 773 | let sum = SumBuilder () 774 | 775 | /// 776 | /// Computes a sum using computation expression syntax. 777 | /// 778 | /// 779 | /// 780 | /// let s = Σ { 1; 2; 3 } 781 | /// 782 | /// 783 | /// let xs = [1..100] 784 | /// let s = Σ { for x in xs -> x } 785 | /// 786 | /// 787 | /// let xs = [4..100] 788 | /// let s = Σ { 1; 2; 3; yield! xs } 789 | /// 790 | /// 791 | let Σ = sum 792 | -------------------------------------------------------------------------------- /FSharp.Collections.Builders/FSharp.Collections.Builders.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net8.0 5 | true 6 | FSharp.Collections.Builders 7 | 1.0.0 8 | Brian Rourke Boll 9 | Computation expressions for conveniently and efficiently constructing common collections. 10 | git 11 | https://github.com/fsprojects/FSharp.Collections.Builders 12 | https://fsprojects.github.io/FSharp.Collections.Builders/ 13 | README.md 14 | MIT 15 | F#;fsharp;collections 16 | logo.png 17 | true 18 | snupkg 19 | © 2024 Brian Rourke Boll 20 | 21 | 22 | $(WarnOn);3390;1182 23 | $(NoWarn);1204 24 | 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | True 33 | \ 34 | 35 | 36 | True 37 | \ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Brian Rourke Boll 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FSharp.Collections.Builders 2 | 3 | This library offers a set of computation expressions for conveniently and efficiently constructing common collections. 4 | 5 | ## Installation 6 | 7 | Get it on NuGet: [FSharp.Collections.Builders](https://www.nuget.org/packages/FSharp.Collections.Builders). 8 | 9 | ```powershell 10 | dotnet add package FSharp.Collections.Builders 11 | ``` 12 | 13 | Or try it in an F# script file (`.fsx`): 14 | 15 | ```fsx 16 | #r "nuget: FSharp.Collections.Builders" 17 | 18 | open FSharp.Collections.Builders 19 | ``` 20 | 21 | ## API documentation 22 | 23 | See the [API documentation](https://fsprojects.github.io/FSharp.Collections.Builders/reference/index.html) 24 | for the full set of supported collections and operations. 25 | 26 | ## Quick start 27 | 28 | The computation expression builders exposed by this library support most of the operations available in the built-in 29 | list, array, and sequence expressions, including `for`, `while`, `yield!`, `try`/`with`, `try`/`finally`, and conditionals.[^1] 30 | 31 | ### `FSharp.Collections.Builders` 32 | 33 | Open `FSharp.Collections.Builders` for type-inference-friendly builders that behave similarly to the built-in list, 34 | array, and sequence expressions in that they treat any collection used with `for` or `yield!` as a `_ seq`. 35 | 36 | ```fsharp 37 | open FSharp.Collections.Builders 38 | ``` 39 | 40 | The builders in this namespace don't require any type annotations in situations like this: 41 | 42 | ```fsharp 43 | // No need to add a type annotation to xs; 44 | // xs is inferred to have type 'a seq. 45 | let f xs = 46 | resizeArray { 47 | for x in xs -> string x 48 | } 49 | ``` 50 | 51 | ## Mutable collections from `System.Collections.Generic` 52 | 53 | ### `resizeArray` 54 | 55 | Enables efficiently constructing and transforming instances of `ResizeArray<'T>` (`System.Collections.Generic.List<'T>`). 56 | 57 | ```fsharp 58 | let xs = resizeArray { 1; 2; 3 } 59 | ``` 60 | 61 | > Compiles to: 62 | > 63 | > ```fsharp 64 | > let xs = ResizeArray () 65 | > xs.Add 1 66 | > xs.Add 2 67 | > xs.Add 3 68 | > ``` 69 | 70 | ```fsharp 71 | let ys = resizeArray { for x in xs -> float x * 2.0 } 72 | ``` 73 | 74 | > Compiles to: 75 | > 76 | > ```fsharp 77 | > let ys = ResizeArray () 78 | > for x in xs do 79 | > ys.Add (float x * 2.0) 80 | > ``` 81 | 82 | ```fsharp 83 | let f xs = resizeArray { for x in xs do if x % 3 = 0 then x } 84 | ``` 85 | 86 | > `xs` is `int seq`. 87 | 88 | ```fsharp 89 | let g xs = resizeArray { for x in xs -> x * x } 90 | ``` 91 | 92 | > `xs` is `float seq`. 93 | 94 | ### `hashSet` 95 | 96 | Enables efficiently constructing and transforming instances of `System.Collections.Generic.HashSet<'T>`. 97 | 98 | ```fsharp 99 | let xs = hashSet { 1; 2; 3 } 100 | ``` 101 | 102 | > `hashSet [1; 2; 3]` 103 | 104 | ```fsharp 105 | let ys = hashSet { yield! xs; yield! xs } 106 | ``` 107 | 108 | > `hashSet [1; 2; 3]` 109 | 110 | ### `sortedSet` 111 | 112 | Enables efficiently constructing and transforming instances of `System.Collections.Generic.SortedSet<'T>`. 113 | 114 | ```fsharp 115 | let xs = sortedSet { 3; 2; 1; 2 } 116 | ``` 117 | 118 | > `sortedSet [1; 2; 3]` 119 | 120 | ### `dictionary` 121 | 122 | Enables efficiently constructing and transforming instances of `System.Collections.Generic.Dictionary<'TKey, 'TValue>`. 123 | 124 | ```fsharp 125 | let kvs = dictionary { 1, "a"; 2, "b"; 3, "c" } 126 | ``` 127 | 128 | ```fsharp 129 | let filtered = dictionary { for k, v in kvs do if k > 1 then k, v } 130 | ``` 131 | 132 | ```fsharp 133 | let list = [1..100] 134 | let stringMap = dictionary { for i in list -> string i, i } 135 | ``` 136 | 137 | ### `sortedDictionary` 138 | 139 | Enables efficiently constructing and transforming instances of `System.Collections.Generic.SortedDictionary<'TKey, 'TValue>`. 140 | 141 | ```fsharp 142 | let m = sortedDictionary { 2, "b"; 3, "c"; 1, "a"; 3, "d" } 143 | ``` 144 | 145 | > `sortedDictionary [1, "a"; 2, "b"; 3, "d"]` 146 | 147 | ## F# collections 148 | 149 | The `set'`[^2] and `map` builders enable ergonomically constructing immutable F# sets and maps 150 | without requiring intermediate collections or the ceremony of folds or recursive functions. 151 | 152 | ### `set'` 153 | 154 | ```fsharp 155 | let xs = set' { 1; 2; 3 } 156 | ``` 157 | 158 | > `set [1; 2; 3]` 159 | 160 | ```fsharp 161 | let ys = set' { 1; 2; 3; 3 } 162 | ``` 163 | 164 | > `set [1; 2; 3]` 165 | 166 | ```fsharp 167 | let xs = [5; 1; 1; 1; 3; 3; 2; 2; 5; 5; 5] 168 | let ys = set' { for x in xs do if x &&& 1 <> 0 then x } 169 | ``` 170 | 171 | > `set [1; 3; 5]` 172 | 173 | ### `map` 174 | 175 | ```fsharp 176 | let m = map { 2, "b"; 3, "c"; 1, "a"; 3, "d" } 177 | ``` 178 | 179 | > `map [1, "a"; 2, "b"; 3, "d"]` 180 | 181 | ```fsharp 182 | let m = map { for x in 1..100 -> x, x * x } 183 | ``` 184 | 185 | > Equivalent to 186 | > 187 | > ```fsharp 188 | > let m = Map.ofSeq (seq { for x in 1..100 -> x, x * x }) 189 | > ``` 190 | > 191 | > or 192 | > 193 | > ```fsharp 194 | > let m = (Map.empty, {1..100}) ||> Seq.fold (fun m x -> m.Add (x, x * x)) 195 | > ``` 196 | 197 | ## Immutable collections from `System.Collections.Immutable` 198 | 199 | ### `immutableArray` 200 | 201 | Enables efficiently constructing and transforming instances of `System.Collections.Immutable.ImmutableArray<'T>`. 202 | 203 | ```fsharp 204 | let xs = immutableArray { 1; 2; 3 } 205 | ``` 206 | 207 | > Compiles to: 208 | > 209 | > ```fsharp 210 | > let xs = 211 | > let builder = ImmutableArray.CreateBuilder () 212 | > builder.Add 1 213 | > builder.Add 2 214 | > builder.Add 3 215 | > builder.ToImmutable () 216 | > ``` 217 | 218 | ```fsharp 219 | let ys = immutableArray { for x in xs -> string x } 220 | ``` 221 | 222 | ### `immutableList` 223 | 224 | ```fsharp 225 | let xs = immutableList { 1; 2; 3 } 226 | ``` 227 | 228 | > `immutableList [1; 2; 3]` 229 | 230 | ### `immutableHashSet` 231 | 232 | ```fsharp 233 | let xs = immutableHashSet { 3; 1; 2; 3 } 234 | ``` 235 | 236 | > `immutableHashSet [3; 1; 2]` 237 | 238 | ### `immutableSortedSet` 239 | 240 | ```fsharp 241 | let xs = immutableSortedSet { 3; 1; 2; 3 } 242 | ``` 243 | 244 | > `immutableSortedSet [1; 2; 3]` 245 | 246 | ### `immutableDictionary` 247 | 248 | ```fsharp 249 | let kvs = immutableDictionary { 1, "a"; 2, "b"; 3, "c" } 250 | ``` 251 | 252 | > `immutableDictionary [1, "a"; 2, "b"; 3, "c"]` 253 | 254 | ### `immutableSortedDictionary` 255 | 256 | ```fsharp 257 | let kvs = immutableSortedDictionary { 2, "b"; 3, "c"; 1, "a"; 3, "d" } 258 | ``` 259 | 260 | > `immutableSortedDictionary [1, "a"; 2, "b"; 3, "d"]` 261 | 262 | ### Summation with `sum`, `Σ` 263 | 264 | Given 265 | 266 | ```fsharp 267 | let xs = [1..100] 268 | ``` 269 | 270 | Instead of 271 | 272 | ```fsharp 273 | let s = 274 | xs 275 | |> List.filter (fun x -> x % 3 = 0) 276 | |> List.sum 277 | ``` 278 | 279 | `sum` enables: 280 | 281 | ```fsharp 282 | let s = sum { for x in xs do if x % 3 = 0 then x } 283 | ``` 284 | 285 | The Greek capital letter sigma `Σ` may read better in certain domains: 286 | 287 | ```fsharp 288 | Σ { for item in items -> item.Subtotal } <= 0.10 * total 289 | ``` 290 | 291 | ### `FSharp.Collections.Builders.Specialized` 292 | 293 | To enable specialized overloads of `for` and `yield!` that give increased iteration performance 294 | at the cost of requiring that the type of the collection being iterated be statically known: 295 | 296 | ```fsharp 297 | open FSharp.Collections.Builders.Specialized 298 | ``` 299 | 300 | ```fsharp 301 | let f (xs : int list) = 302 | resizeArray { 303 | for x in xs -> x * x 304 | } 305 | ``` 306 | 307 | > Compiles down to a fast `'T list` iteration. 308 | 309 | ```fsharp 310 | let g xs = 311 | let len = Array.length xs 312 | resizeArray { 313 | for x in xs -> x * len 314 | } 315 | ``` 316 | 317 | > Compiles down to a fast integer `for`-loop. 318 | 319 | ## Motivation 320 | 321 | F#'s built-in [list](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/lists#creating-and-initializing-lists), 322 | [array](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/arrays#create-arrays), 323 | and [sequence](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/sequences#sequence-expressions) expressions 324 | make initializing and transforming `'T list`, `'T array`, and `'T seq` quite nice: 325 | 326 | #### List literal 327 | 328 | ```fsharp 329 | let nums = [1; 2; 3] 330 | ``` 331 | 332 | #### List expression with `for` and `->` 333 | 334 | ```fsharp 335 | let doubled = [ for num in nums -> float num * 2.0 ] 336 | ``` 337 | 338 | #### Array expression with `for` and `->` 339 | 340 | ```fsharp 341 | let doubledArr = [| for num in nums -> float num * 2.0 |] 342 | ``` 343 | 344 | #### Sequence expression with `for` and `->` 345 | 346 | ```fsharp 347 | let doubledSeq = seq { for num in nums -> float num * 2.0 } 348 | ``` 349 | 350 | But when it comes time to work with one of the common mutable collection types from `System.Collections.Generic`, 351 | whether to interoperate with other .NET libraries or for specific performance or modeling reasons, F# doesn't 352 | provide the same syntactic sugar, forcing you you to switch modes from expression-based to statement-based style: 353 | 354 | ```fsharp 355 | let nums = ResizeArray () 356 | nums.Add 1 357 | nums.Add 2 358 | nums.Add 3 359 | ``` 360 | 361 | Or, to keep the ergonomics of sequence expressions, you must instantiate and iterate over intermediate collections: 362 | 363 | #### Instantiates and iterates over an intermediate `int list` 364 | 365 | ```fsharp 366 | let nums = ResizeArray [1; 2; 3] 367 | ``` 368 | 369 | #### Instantiates and iterates over an intermediate `int seq` 370 | 371 | ```fsharp 372 | let nums = ResizeArray (seq { 1; 2; 3 }) 373 | ``` 374 | 375 | ### Ergonomic collection initialization beyond lists, arrays, and sequences 376 | 377 | C# offers collection initialization syntax for types that implement `IEnumerable` and have a public `Add` method: 378 | 379 | ```csharp 380 | var nums = new List { 1, 2, 3 }; 381 | var nums = new HashSet { 1, 2, 3 }; 382 | ``` 383 | 384 | Or, with target-typed `new()`: 385 | 386 | ```csharp 387 | List nums = new() { 1, 2, 3 }; 388 | HashSet nums = new() { 1, 2, 3 }; 389 | ``` 390 | 391 | F# 6's [resumable code](https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1087-resumable-code.md) feature 392 | makes it straightforward to implement efficient, ergonomic computation expression builders 393 | for collection types that aren't special-cased by the F# compiler. 394 | 395 | This library implements such builders for several common mutable and immutable collections from `System.Collections.Generic` and `System.Collections.Immutable`, and `FSharp.Collections`, 396 | as well as offering generic `collection` and `dict'` builders that support any collection type with a default constructor and an appropriate `Add` method. 397 | 398 | ## Future 399 | 400 | There are a couple language suggestions that might someday (happily!) make parts of this library obsolete: 401 | 402 | - https://github.com/fsharp/fslang-suggestions/issues/1086 403 | - https://github.com/fsharp/fslang-suggestions/issues/619 404 | 405 | Additional potential development directions: 406 | 407 | - Add versions that take initial capacities, equality comparers, etc. 408 | - Add a vectorized version of the `sum` expression. 409 | 410 | [^1]: It is not yet possible to provide custom implementations of the range operator `(..)` for computation expression builders—although there is an [approved language suggestion](https://github.com/fsharp/fslang-suggestions/issues/1116) for it. 411 | [^2]: Alas, unlike `seq`, which is special-cased by the compiler and can act as both a function and computation expression builder, it is impossible to do the same with the built-in `set` function (without it being similarly special-cased in the compiler). 412 | -------------------------------------------------------------------------------- /docs/content/fsdocs-theme.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Berkeley Mono'; 3 | src: local('Berkeley Mono'), 4 | url('https://fonts.brb.engineering/BerkeleyMono/Regular/font.woff2') format('woff2'); 5 | font-weight: normal; 6 | font-style: normal; 7 | font-display: swap; 8 | } 9 | 10 | @font-face { 11 | font-family: 'Berkeley Mono'; 12 | src: local('Berkeley Mono'), 13 | url('https://fonts.brb.engineering/BerkeleyMono/Italic/font.woff2') format('woff2'); 14 | font-weight: normal; 15 | font-style: italic; 16 | font-display: swap; 17 | } 18 | 19 | @font-face { 20 | font-family: 'Berkeley Mono'; 21 | src: local('Berkeley Mono'), 22 | url('https://fonts.brb.engineering/BerkeleyMono/Bold/font.woff2') format('woff2'); 23 | font-weight: bold; 24 | font-style: normal; 25 | font-display: swap; 26 | } 27 | 28 | @font-face { 29 | font-family: 'Berkeley Mono'; 30 | src: local('Berkeley Mono'), 31 | url('https://fonts.brb.engineering/BerkeleyMono/BoldItalic/font.woff2') format('woff2'); 32 | font-weight: bold; 33 | font-style: italic; 34 | font-display: swap; 35 | } 36 | 37 | :root { 38 | --monospace-font: 'Berkeley Mono', 'Cascadia Code', 'Fira Code', monospace; 39 | } 40 | 41 | pre, 42 | code, 43 | .fsdocs-tip, 44 | .fssnip { 45 | font-feature-settings: 'ss03', 'zero', 'calt'; 46 | } 47 | 48 | h1 code, 49 | h2 code, 50 | h3 code, 51 | h4 code, 52 | h5 code, 53 | h6 code { 54 | font-weight: 300; 55 | font-size: unset; 56 | } 57 | -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Collections.Builders/98d07e648983ace7ce66169026117a6915782ea1/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Collections.Builders/98d07e648983ace7ce66169026117a6915782ea1/docs/img/logo.png -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Collections.Builders/98d07e648983ace7ce66169026117a6915782ea1/logo.png --------------------------------------------------------------------------------