Collection Computation Expressions

FSharpWrap automatically generates computation expressions for immutable and mutable collection types that implement IEnumerable<'T>.

Conditionally Generated Methods

These methods are only generated for the computation expression type when a specific member is defined on the collection type.

Yield method

In order for a generated computation expression to be usable, collection types need at least an Add, Push, or Enqueue method that takes onle one parameters with a return type either equal to the type of the collection or void.

For dictionary types, an Add method that takes two parameters instead of one is also allowed.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
open System.Collections.Immutable
open System.Collections.Generic

// Mutable type
let a =
    List.expr {
        0 // Uses `Add` method under the hood
        1
        2
    }
    |> Array.ofSeq // Allow the items to be seen in the output

let b =
    ImmutableList.expr {
        3 // Uses an immutable `Add` method under the hood
        4
        5
    }
    |> Array.ofSeq

let c =
    ImmutableDictionary.expr {
        yield "hello", "world" // Uses an `Add` method with two parameters
        yield "triglycerides", "fatty acid"
        yield "key", "value"
    }
    |> Array.ofSeq
val a : int [] = [|0; 1; 2|]
val b : int [] = [|3; 4; 5|]
val c : System.Collections.Generic.KeyValuePair<string,string> [] =
  [|[hello, world]; [key, value]; [triglycerides, fatty acid]|]

YieldFrom method

Only defined when the collection type defines an AddRange method that takes only one parameter.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
open System.Collections.Immutable

let d =
    ImmutableList.expr {
        yield! b
    }
    |> Array.ofSeq
val d : int [] = [|3; 4; 5|]

Zero method

Defined when the collection type defines a parameterless constructor or defines a static field named Empty with a type that is the same as the collection type.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
open System.Collections.Immutable

let e =
    ImmutableList.expr {
        if 1 = 0 then
            yield 1
        // `Empty` field is being used here
    }
    |> Array.ofSeq
val e : int [] = [||]

Always Generated Methods

These methods are always generated no matter what members are defined on the collection type.

For method

Allows the use of for loops inside the computation expression.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
open System

let f =
    ImmutableList.expr {
        for i = 97 to 102 do char i
    }
    |> String.Concat
val f : string = "abcdef"

TryFinally method

Allows the use of a try...finally expression within the computation expression.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
open System.Collections.Immutable

let g =
    ImmutableList.expr {
        try
            1
            2
            3
        finally
            printfn "Hello"
    }
    |> Array.ofSeq
val g : int [] = [|1; 2; 3|]

Using method

Allows the use of use bindings within the computation expression.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
open System
open System.IO
open System.Collections.Immutable

let h =
    ImmutableList.expr {
        use stream = new MemoryStream(16)
        stream.Write(Array.replicate 16 5uy, 0, 16)
        yield! stream.GetBuffer()
    }
    |> Array.ofSeq
val h : byte [] =
  [|5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy; 5uy;
    5uy|]
namespace System
namespace System.Collections
namespace System.Collections.Immutable
namespace System.Collections.Generic
val a : int []
Multiple items
type List<'T> =
  new : unit -> List<'T> + 2 overloads
  member Add : item:'T -> unit
  member AddRange : collection:IEnumerable<'T> -> unit
  member AsReadOnly : unit -> ReadOnlyCollection<'T>
  member BinarySearch : item:'T -> int + 2 overloads
  member Capacity : int with get, set
  member Clear : unit -> unit
  member Contains : item:'T -> bool
  member ConvertAll<'TOutput> : converter:Converter<'T, 'TOutput> -> List<'TOutput>
  member CopyTo : array:'T[] -> unit + 2 overloads
  ...
  nested type Enumerator

--------------------
List() : List<'T>
List(capacity: int) : List<'T>
List(collection: IEnumerable<'T>) : List<'T>
val internal expr : List.ListBuilder
module Array

from Microsoft.FSharp.Collections
val ofSeq : source:seq<'T> -> 'T []
val b : int []
Multiple items
type ImmutableList =
  static member Create<'T> : unit -> ImmutableList<'T> + 2 overloads
  static member CreateBuilder<'T> : unit -> Builder<'T>
  static member CreateRange<'T> : items:IEnumerable<'T> -> ImmutableList<'T>
  static member IndexOf<'T> : list:IImmutableList<'T> * item:'T -> int + 3 overloads
  static member LastIndexOf<'T> : list:IImmutableList<'T> * item:'T -> int + 3 overloads
  static member Remove<'T> : list:IImmutableList<'T> * value:'T -> IImmutableList<'T>
  static member RemoveRange<'T> : list:IImmutableList<'T> * items:IEnumerable<'T> -> IImmutableList<'T>
  static member Replace<'T> : list:IImmutableList<'T> * oldValue:'T * newValue:'T -> IImmutableList<'T>
  static member ToImmutableList<'TSource> : source:IEnumerable<'TSource> -> ImmutableList<'TSource> + 1 overload

--------------------
type ImmutableList<'T> =
  member Add : value:'T -> ImmutableList<'T>
  member AddRange : items:IEnumerable<'T> -> ImmutableList<'T>
  member BinarySearch : item:'T -> int + 2 overloads
  member Clear : unit -> ImmutableList<'T>
  member Contains : value:'T -> bool
  member ConvertAll<'TOutput> : converter:Func<'T, 'TOutput> -> ImmutableList<'TOutput>
  member CopyTo : array:'T[] -> unit + 2 overloads
  member Count : int
  member Exists : match:Predicate<'T> -> bool
  member Find : match:Predicate<'T> -> 'T
  ...
  nested type Builder
  nested type Enumerator
val internal expr : ImmutableList.ImmutableListBuilder
val c : KeyValuePair<string,string> []
Multiple items
type ImmutableDictionary =
  static member Contains<'TKey, 'TValue> : map:IImmutableDictionary<'TKey, 'TValue> * key:'TKey * value:'TValue -> bool
  static member Create<'TKey, 'TValue> : unit -> ImmutableDictionary<'TKey, 'TValue> + 2 overloads
  static member CreateBuilder<'TKey, 'TValue> : unit -> Builder<'TKey, 'TValue> + 2 overloads
  static member CreateRange<'TKey, 'TValue> : items:IEnumerable<KeyValuePair<'TKey, 'TValue>> -> ImmutableDictionary<'TKey, 'TValue> + 2 overloads
  static member GetValueOrDefault<'TKey, 'TValue> : dictionary:IImmutableDictionary<'TKey, 'TValue> * key:'TKey -> 'TValue + 1 overload
  static member ToImmutableDictionary<'TKey, 'TValue> : builder:Builder<'TKey, 'TValue> -> ImmutableDictionary<'TKey, 'TValue> + 8 overloads

--------------------
type ImmutableDictionary<'TKey,'TValue> =
  member Add : key:'TKey * value:'TValue -> ImmutableDictionary<'TKey, 'TValue>
  member AddRange : pairs:IEnumerable<KeyValuePair<'TKey, 'TValue>> -> ImmutableDictionary<'TKey, 'TValue>
  member Clear : unit -> ImmutableDictionary<'TKey, 'TValue>
  member Contains : pair:KeyValuePair<'TKey, 'TValue> -> bool
  member ContainsKey : key:'TKey -> bool
  member ContainsValue : value:'TValue -> bool
  member Count : int
  member GetEnumerator : unit -> Enumerator<'TKey, 'TValue>
  member IsEmpty : bool
  member Item : 'TKey -> 'TValue
  ...
  nested type Builder
  nested type Enumerator
val internal expr : ImmutableDictionary.ImmutableDictionaryBuilder
val d : int []
val e : int []
val f : string
val i : int
Multiple items
val char : value:'T -> char (requires member op_Explicit)

--------------------
type char = Char
Multiple items
type String =
  new : value:char[] -> string + 8 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool + 3 overloads
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 3 overloads
  member EnumerateRunes : unit -> StringRuneEnumerator
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  ...

--------------------
String(value: char []) : String
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: ReadOnlySpan<char>) : String
String(c: char, count: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
String.Concat([<ParamArray>] values: string []) : string
   (+0 other overloads)
String.Concat(values: IEnumerable<string>) : string
   (+0 other overloads)
String.Concat<'T>(values: IEnumerable<'T>) : string
   (+0 other overloads)
String.Concat([<ParamArray>] args: obj []) : string
   (+0 other overloads)
String.Concat(arg0: obj) : string
   (+0 other overloads)
String.Concat(str0: ReadOnlySpan<char>, str1: ReadOnlySpan<char>) : string
   (+0 other overloads)
String.Concat(str0: string, str1: string) : string
   (+0 other overloads)
String.Concat(arg0: obj, arg1: obj) : string
   (+0 other overloads)
String.Concat(str0: ReadOnlySpan<char>, str1: ReadOnlySpan<char>, str2: ReadOnlySpan<char>) : string
   (+0 other overloads)
String.Concat(str0: string, str1: string, str2: string) : string
   (+0 other overloads)
val g : int []
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...
namespace System.IO
val h : byte []
val stream : MemoryStream
Multiple items
type MemoryStream =
  inherit Stream
  new : unit -> MemoryStream + 6 overloads
  member CanRead : bool
  member CanSeek : bool
  member CanWrite : bool
  member Capacity : int with get, set
  member CopyTo : destination:Stream * bufferSize:int -> unit
  member CopyToAsync : destination:Stream * bufferSize:int * cancellationToken:CancellationToken -> Task
  member Flush : unit -> unit
  member FlushAsync : cancellationToken:CancellationToken -> Task
  member GetBuffer : unit -> byte[]
  ...

--------------------
MemoryStream() : MemoryStream
MemoryStream(capacity: int) : MemoryStream
MemoryStream(buffer: byte []) : MemoryStream
MemoryStream(buffer: byte [], writable: bool) : MemoryStream
MemoryStream(buffer: byte [], index: int, count: int) : MemoryStream
MemoryStream(buffer: byte [], index: int, count: int, writable: bool) : MemoryStream
MemoryStream(buffer: byte [], index: int, count: int, writable: bool, publiclyVisible: bool) : MemoryStream
val replicate : count:int -> initial:'T -> 'T []