├── .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
--------------------------------------------------------------------------------