Integrated Random Testing

For a while I've been annoyed by the performance of testing libraries in general, but also with how random testing and performance testing are not better integrated and multithreaded. Testing libraries like Expecto do a great job of improving performance by running unit tests in parallel while also opening up useful functionality like stress testing. I want to take this further with a new prototype.

The goal is a simpler, more lightweight testing library with faster, more integrated parallel random testing with automatic parallel shrinking.

The library aims to encourage the shift from a number of unit and regression tests with hard coded input and output data to fewer more general random tests. This idea is covered well by John Hughes in Don't write tests! and the idea of One test to rule them all. Key takeaways are general random tests can provide more coverage for less test code, and larger test cases have a higher probability of finding a failure for a given execution time.

Asserts are no longer exception based and all are evaluated - More than one per test is encouraged. Simpler setup and faster for multi part testing.

test "PCG demo 1" { let pcg = PCG . TryParse "36185706b82c2e03f8" |> Option . get Test . equal pcg . Stream 54 "stream" Test . equal pcg . State 0x185706b82c2e03f8UL "state" let expectedNext = [| 0xa15c02b7u ; 0x7b47f409u |] // ... let expectedState = [| 0x2b47fed88766bb05UL ; 0x8b33296d19bf5b4eUL |] // ... for i = 0 to expectedNext . Length - 1 do Test . equal ( pcg . Next ( ) ) expectedNext . [ i ] ( "n" + string i ) Test . equal pcg . State expectedState . [ i ] ( "s" + string i ) }

Integrated random testing - Simpler syntax. Easier to move to more general random testing. Run in fine grained parallel.

test "gen" { test "int" { let! s = Gen . int let! l = Gen . int . [ 0.. Int32 . MaxValue - s ] let! i = Gen . int . [ s .. s + l ] Test . between i s ( s + l ) "between" } test "int distribution" { let freq = 10 let buckets = 1000 let! ints = Gen . seq . [ freq * buckets ] Gen . int . [ 0.. buckets - 1 ] let actual = Array . zeroCreate buckets Seq . iter ( fun i -> actual . [ i ] <- actual . [ i ] + 1 ) ints let expected = Array . create buckets freq Test . chiSquared actual expected "chi-squared" }

No sizing or number of runs for random tests - Instead use distributions. More realistic large test cases.

test "list rev does nothing not" { let! list = let f ma mi bu = Version ( int ma , int mi , int bu ) Gen . map3 f Gen . byte Gen . byte Gen . byte |> Gen . list . [ 0.. 100 ] Test . equal ( List . rev list ) list "rev equal" }

Automatic parallel random shrinking giving a reproducible seed - Smaller candidates found using a fast PCG loop. Simpler reproducible examples.

Stress testing in parallel across unit and random tests using PCG streams - Low sync, high performance, fine grained parallel testing.

test "multithreading" { let n = 10 let ms = MapSlim ( ) test "update" { let! i = Gen . int . [ .. n - 1 ] let v = & ms . GetRef i v <- 1 - v } test "get" { let! i = Gen . int . [ .. n - 1 ] let v = defaultValueArg ( ms . GetOption i ) 0 Test . isTrue ( v = 0 || v = 1 ) "get is 0 or 1" } test "item" { if ms . Count > 0 then let! i = Gen . int . [ .. ms . Count - 1 ] let k , v = ms . Item i Test . lessThan k n "key is ok" Test . isTrue ( v = 0 || v = 1 ) "value is 0 or 1" } }

Integrated performance testing - Performance tests can be random and run in parallel with statistics collected across all threads.

test "mapslim" { test "performance" { test "get" { let ms = MapSlim ( ) let dict = Dictionary ( ) let! n = Gen . int . [ 1.. 100 ] let! keys = Gen . array . [ n ] Gen . int . [ - 1000.. 1000 ] |> Gen . map ( Array . mapi ( fun i h -> let k = KeyWithHash ( uint64 i , h ) ms . Set ( k , k ) dict . Add ( k , k ) k ) ) Test . faster ( fun ( ) -> for i = 0 to n - 1 do ms . GetOption keys . [ i ] |> ignore ) ( fun ( ) -> for i = 0 to n - 1 do dict . TryGetValue keys . [ i ] |> ignore ) "get" } // ... } // ... }

Tests are run in parallel using continuations - Fine grained, in test asynchronous code to make each test faster.

test "reference" { let getTest name ( gen : Gen < ' a > ) = test name { let! items = Gen . tuple gen Gen . int |> Gen . list . [ .. 100 ] let! check = gen let! expectedFork = io { return List . fold ( fun m ( k , v ) -> Map . add k v m ) Map . empty items |> Map . tryFind check } |> IO . fork let actual = let ms = MapSlim ( ) List . iter ms . Set items ms . GetOption check |> function | ValueSome i -> Some i | ValueNone -> None let! expected = expectedFork Test . equal actual expected "check value equal" } getTest "get byte" Gen . byte getTest "get char" Gen . char getTest "get int" Gen . int . [ .. 10 ] getTest "get uint" Gen . uint . [ .. 10u ] getTest "get string" Gen . string }

The prototype currently has no dependencies and is a single file for the library, one for Gen and one for Test. They can easily be copied into a project to try them out, and new Gen and Test functions added.

The library is still in an early stage. It is missing more tests, label functionality, async io and needs a tidy and performance work.

I am keen to share it now to see if there are further ideas. Some of the functionality if successful could be added to existing projects or it could form its own. It is unclear at this point.

The code can be found here.

module IRT

namespace System

namespace System.Threading

namespace System.Diagnostics

namespace System.Globalization

namespace System.Runtime

namespace System.Runtime.CompilerServices

namespace System.Runtime.InteropServices

namespace Microsoft

namespace Microsoft.FSharp

namespace Microsoft.FSharp.Core

PCG.Inc: uint64

Multiple items

val uint64 : value:'T -> uint64 (requires member op_Explicit)



--------------------

type uint64 = UInt64

PCG.State: uint64

val inc : uint64

val state : uint64

val stream : int

Multiple items

val int : value:'T -> int (requires member op_Explicit)



--------------------

type int = int32



--------------------

type int<'Measure> = int

val seed : uint64

Multiple items

type PCG =

new : stream:int -> PCG

private new : inc:uint64 * state:uint64 -> PCG

new : stream:int * seed:uint64 -> PCG

val Inc: uint64

val mutable State: uint64

member Next : unit -> uint32

member Next : maxExclusive:int -> int

member Next64 : unit -> uint64

member Next64 : maxExclusive:int64 -> int64

override ToString : unit -> string

...



--------------------

new : stream:int -> PCG

new : stream:int * seed:uint64 -> PCG

private new : inc:uint64 * state:uint64 -> PCG

Multiple items

type Stopwatch =

new : unit -> Stopwatch

member Elapsed : TimeSpan

member ElapsedMilliseconds : int64

member ElapsedTicks : int64

member IsRunning : bool

member Reset : unit -> unit

member Restart : unit -> unit

member Start : unit -> unit

member Stop : unit -> unit

static val Frequency : int64

...



--------------------

Stopwatch() : Stopwatch

Stopwatch.GetTimestamp() : int64

val i : PCG

val sprintf : format:Printf.StringFormat<'T> -> 'T

val s : string

Multiple items

val string : value:'T -> string



--------------------

type string = String

val l : int

property String.Length: int

val mutable stream : int

module Unchecked



from Microsoft.FSharp.Core.Operators

val defaultof<'T> : 'T

val mutable state : uint64

type Int32 =

struct

member CompareTo : value:obj -> int + 1 overload

member Equals : obj:obj -> bool + 1 overload

member GetHashCode : unit -> int

member GetTypeCode : unit -> TypeCode

member ToString : unit -> string + 3 overloads

static val MaxValue : int

static val MinValue : int

static member Parse : s:string -> int + 3 overloads

static member TryParse : s:string * result:int -> bool + 1 overload

end

Int32.TryParse(s: string, result: byref<int>) : bool

Int32.TryParse(s: string, style: NumberStyles, provider: IFormatProvider, result: byref<int>) : bool

String.Substring(startIndex: int) : string

String.Substring(startIndex: int, length: int) : string

type NumberStyles =

| None = 0

| AllowLeadingWhite = 1

| AllowTrailingWhite = 2

| AllowLeadingSign = 4

| AllowTrailingSign = 8

| AllowParentheses = 16

| AllowDecimalPoint = 32

| AllowThousands = 64

| AllowExponent = 128

| AllowCurrencySymbol = 256

...

field NumberStyles.HexNumber: NumberStyles = 515

type UInt64 =

struct

member CompareTo : value:obj -> int + 1 overload

member Equals : obj:obj -> bool + 1 overload

member GetHashCode : unit -> int

member GetTypeCode : unit -> TypeCode

member ToString : unit -> string + 3 overloads

static val MaxValue : uint64

static val MinValue : uint64

static member Parse : s:string -> uint64 + 3 overloads

static member TryParse : s:string * result:uint64 -> bool + 1 overload

end

UInt64.TryParse(s: string, result: byref<uint64>) : bool

UInt64.TryParse(s: string, style: NumberStyles, provider: IFormatProvider, result: byref<uint64>) : bool

union case Option.Some: Value: 'T -> Option<'T>

union case Option.None: Option<'T>

val p : PCG

val oldstate : uint64

val xorshifted : uint32

Multiple items

val uint32 : value:'T -> uint32 (requires member op_Explicit)



--------------------

type uint32 = UInt32

val rot : int

member PCG.Next : unit -> uint32

member PCG.Next : maxExclusive:int -> int

val maxExclusive : int

val bound : uint32

val threshold : uint32

val find : (unit -> int)

val r : uint32

val maxExclusive : int64

Multiple items

val int64 : value:'T -> int64 (requires member op_Explicit)



--------------------

type int64 = Int64



--------------------

type int64<'Measure> = int64

val bound : uint64

val threshold : uint64

val find : (unit -> int64)

val r : uint64

member PCG.Next64 : unit -> uint64

member PCG.Next64 : maxExclusive:int64 -> int64

Multiple items

module Result



from Microsoft.FSharp.Core



--------------------

[<Struct>]

type Result<'T,'TError> =

| Ok of ResultValue: 'T

| Error of ErrorValue: 'TError

val private traverse : f:('a -> Result<'b,'c>) -> list:'a list -> Result<'b list,'c list>

val f : ('a -> Result<'b,'c>)

Multiple items

val list : 'a list



--------------------

type 'T list = List<'T>

Multiple items

module List



from Microsoft.FSharp.Collections



--------------------

type List<'T> =

| ( [] )

| ( :: ) of Head: 'T * Tail: 'T list

interface IReadOnlyList<'T>

interface IReadOnlyCollection<'T>

interface IEnumerable

interface IEnumerable<'T>

member GetSlice : startIndex:int option * endIndex:int option -> 'T list

member Head : 'T

member IsEmpty : bool

member Item : index:int -> 'T with get

member Length : int

member Tail : 'T list

...

val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State

[<Struct>]

val s : Result<'b list,'c list>

val i : 'a

union case Result.Ok: ResultValue: 'T -> Result<'T,'TError>

val l : 'b list

val h : 'b

union case Result.Error: ErrorValue: 'TError -> Result<'T,'TError>

val l : 'c list

val e : 'c

val h : 'c

val private sequence : list:Result<'a,'b> list -> Result<'a list,'b list>

Multiple items

val list : Result<'a,'b> list



--------------------

type 'T list = List<'T>

val id : x:'T -> 'T

namespace System.Text

union case Text.For: string -> Text

union case Text.Grey: string -> Text

union case Text.Red: string -> Text

union case Text.BrightRed: string -> Text

union case Text.Green: string -> Text

union case Text.BrightGreen: string -> Text

union case Text.Yellow: string -> Text

union case Text.BrightYellow: string -> Text

union case Text.Blue: string -> Text

union case Text.BrightBlue: string -> Text

union case Text.Magenta: string -> Text

union case Text.BrightMagenta: string -> Text

union case Text.Cyan: string -> Text

union case Text.BrightCyan: string -> Text

Multiple items

union case Text.Text: struct (Text * Text) -> Text



--------------------

namespace System.Text



--------------------

type Text =

| For of string

| Grey of string

| Red of string

| BrightRed of string

| Green of string

| BrightGreen of string

| Yellow of string

| BrightYellow of string

| Blue of string

| BrightBlue of string

...

static member ( + ) : t1:Text * t2:Text -> Text

val t1 : Text

val t2 : Text

Multiple items

type LiteralAttribute =

inherit Attribute

new : unit -> LiteralAttribute



--------------------

new : unit -> LiteralAttribute

val private reset : string

val private toANSIList : t:Text -> string list

val t : Text

val toANSI : t:Text -> string

Multiple items

type String =

new : value:char -> string + 7 overloads

member Chars : int -> char

member Clone : unit -> obj

member CompareTo : value:obj -> int + 1 overload

member Contains : value:string -> bool

member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit

member EndsWith : value:string -> bool + 2 overloads

member Equals : obj:obj -> bool + 2 overloads

member GetEnumerator : unit -> CharEnumerator

member GetHashCode : unit -> int

...



--------------------

String(value: nativeptr<char>) : String

String(value: nativeptr<sbyte>) : String

String(value: char []) : String

String(c: char, count: int) : String

String(value: nativeptr<char>, startIndex: int, length: int) : String

String(value: nativeptr<sbyte>, startIndex: int, length: int) : String

String(value: char [], 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: Collections.Generic.IEnumerable<string>) : string

(+0 other overloads)

String.Concat<'T>(values: Collections.Generic.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: string, str1: string) : string

(+0 other overloads)

String.Concat(arg0: obj, arg1: obj) : string

(+0 other overloads)

String.Concat(str0: string, str1: string, str2: string) : string

(+0 other overloads)

String.Concat(arg0: obj, arg1: obj, arg2: obj) : string

(+0 other overloads)

String.Concat(str0: string, str1: string, str2: string, str3: string) : string

(+0 other overloads)

ListSlim.count: int

ListSlim.entries: 'k []

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

...

val empty<'T> : 'T []

val capacity : int

val zeroCreate : count:int -> 'T []

val m : ListSlim<'k>

val i : int

val set : elements:seq<'T> -> Set<'T> (requires comparison)

val v : 'k

val key : 'k

property Array.Length: int

val newEntries : 'k []

Array.Copy(sourceArray: Array, destinationArray: Array, length: int64) : unit

Array.Copy(sourceArray: Array, destinationArray: Array, length: int) : unit

Array.Copy(sourceArray: Array, sourceIndex: int64, destinationArray: Array, destinationIndex: int64, length: int64) : unit

Array.Copy(sourceArray: Array, sourceIndex: int, destinationArray: Array, destinationIndex: int, length: int) : unit

val init : count:int -> initializer:(int -> 'T) -> 'T []

val get : array:'T [] -> index:int -> 'T

val init : length:int -> initializer:(int -> 'T) -> 'T list

Multiple items

type StructAttribute =

inherit Attribute

new : unit -> StructAttribute



--------------------

new : unit -> StructAttribute

type private Entry<'k,'v> =

struct

val mutable bucket: int

val mutable key: 'k

val mutable value: 'v

val mutable next: int

end

Entry.bucket: int

Entry.key: 'k

Entry.value: 'v

Entry.next: int

Multiple items

type private InitialHolder<'k,'v> =

new : unit -> InitialHolder<'k,'v>

static member Initial : Entry<'k,'v> []



--------------------

private new : unit -> InitialHolder<'k,'v>

val initial : Entry<'k,'v> []

type IEquatable<'T> =

member Equals : other:'T -> bool

MapSlim.count: int

MapSlim.entries: Entry<'k,'v> []

property InitialHolder.Initial: Entry<'k,'v> []

val powerOf2 : (int -> int)

val v : int

val twos : (int -> int)

val m : MapSlim<'k,'v> (requires equality and 'k :> IEquatable<'k>)

val oldEntries : Entry<'k,'v> [] (requires equality and 'k :> IEquatable<'k>)

val entries : Entry<'k,'v> [] (requires equality and 'k :> IEquatable<'k>)

val bi : int

Multiple items

type MethodImplAttribute =

inherit Attribute

new : unit -> MethodImplAttribute + 2 overloads

val MethodCodeType : MethodCodeType

member Value : MethodImplOptions



--------------------

MethodImplAttribute() : MethodImplAttribute

MethodImplAttribute(methodImplOptions: MethodImplOptions) : MethodImplAttribute

MethodImplAttribute(value: int16) : MethodImplAttribute

type MethodImplOptions =

| Unmanaged = 4

| ForwardRef = 16

| PreserveSig = 128

| InternalCall = 4096

| Synchronized = 32

| NoInlining = 8

| AggressiveInlining = 256

| NoOptimization = 64

field MethodImplOptions.NoInlining: MethodImplOptions = 8

val key : 'k (requires equality and 'k :> IEquatable<'k>)

val hashCode : int

member private MapSlim.Resize : unit -> unit

val bucketIndex : int

val value : 'v

Object.GetHashCode() : int

val mutable i : int

val not : value:bool -> bool

Object.Equals(obj: obj) : bool

IEquatable.Equals(other: 'k) : bool

val v : byref<'v>

member private MapSlim.AddKey : key:'k * hashCode:int -> byref<'v>

type byref<'T> = (# "<Common IL Type Omitted>" #)

val added : outref<bool>

type bool = Boolean

type outref<'T> = outref<'T>

[<Struct>]

type 'T voption = ValueOption<'T>

union case ValueOption.ValueSome: 'T -> ValueOption<'T>

union case ValueOption.ValueNone: ValueOption<'T>

val entries : Entry<'k,'v> (requires equality and 'k :> IEquatable<'k>)

Multiple items

type AllowNullLiteralAttribute =

inherit Attribute

new : unit -> AllowNullLiteralAttribute

new : value:bool -> AllowNullLiteralAttribute

member Value : bool



--------------------

new : unit -> AllowNullLiteralAttribute

new : value:bool -> AllowNullLiteralAttribute

Size.I: uint64

Size.L: Size list

Multiple items

type Size =

interface IComparable

interface IComparable<Size>

new : i:uint64 * l:Size list -> Size

val I: uint64

val L: Size list

override Equals : y:obj -> bool

override GetHashCode : unit -> int

static member zero : Size



--------------------

new : i:uint64 * l:Size list -> Size

type 'T list = List<'T>

val i : uint64

val l : Size list

val x : Size

val y : obj

Multiple items

type IComparable =

member CompareTo : obj:obj -> int



--------------------

type IComparable<'T> =

member CompareTo : other:'T -> int

val y : Size

val compare : (Size -> Size -> int64)

val i : int64

val fold2 : folder:('State -> 'T1 -> 'T2 -> 'State) -> state:'State -> list1:'T1 list -> list2:'T2 list -> 'State

val s : int64

val sign : value:'T -> int (requires member get_Sign)

type Gen<'a> =

interface

abstract member Gen : PCG -> 'a * Size

end

Multiple items

type PCG =

new : stream:int -> PCG

private new : inc:uint64 * state:uint64 -> PCG

new : stream:int * seed:uint64 -> PCG

val Inc: uint64

val mutable State: uint64

member Next : unit -> uint32

member Next : maxExclusive:int -> int

member Next64 : unit -> uint64

member Next64 : maxExclusive:int64 -> int64

override ToString : unit -> string

...



--------------------

new : stream:int -> PCG

new : stream:int * seed:uint64 -> PCG

type GenRange<'a,'b> =

interface

inherit Gen<'b>

abstract member GetSlice : 'a option * 'a option -> Gen<'b>

end

type 'T option = Option<'T>

Multiple items

type GenBuilder =

new : unit -> GenBuilder

new : Gen:obj -> GenBuilder



--------------------

new : unit -> GenBuilder

new : Gen:obj -> GenBuilder

val g : unit * Size

property Size.zero: Size

Multiple items

val Gen : obj



--------------------

type Gen<'a> =

interface

abstract member Gen : PCG -> 'a * Size

end

val fst : tuple:('T1 * 'T2) -> 'T1

type obj = Object

Multiple items

union case Text.Text: struct (Text * Text) -> Text



--------------------

module Text



from IRT



--------------------

namespace System.Text



--------------------

type Text =

| For of string

| Grey of string

| Red of string

| BrightRed of string

| Green of string

| BrightGreen of string

| Yellow of string

| BrightYellow of string

| Blue of string

| BrightBlue of string

...

static member ( + ) : t1:Text * t2:Text -> Text

Multiple items

val Failure : message:string -> exn



--------------------

active recognizer Failure: exn -> string option

Multiple items

type Exception =

new : unit -> Exception + 2 overloads

member Data : IDictionary

member GetBaseException : unit -> Exception

member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit

member GetType : unit -> Type

member HResult : int with get, set

member HelpLink : string with get, set

member InnerException : Exception

member Message : string

member Source : string with get, set

...



--------------------

Exception() : Exception

Exception(message: string) : Exception

Exception(message: string, innerException: exn) : Exception

type exn = Exception

Multiple items

type ListSlim<'k> =

new : unit -> ListSlim<'k>

new : capacity:int -> ListSlim<'k>

val mutable private count: int

val mutable private entries: 'k []

member Add : key:'k -> int

member ToArray : unit -> 'k []

member ToList : unit -> 'k list

member Count : int

member Item : i:int -> 'k with get

member Item : i:int -> 'k with set



--------------------

new : unit -> ListSlim<'k>

new : capacity:int -> ListSlim<'k>

val exists : predicate:('T -> bool) -> list:'T list -> bool

namespace System.IO

val failwith : message:string -> 'T

Multiple items

type AutoOpenAttribute =

inherit Attribute

new : unit -> AutoOpenAttribute

new : path:string -> AutoOpenAttribute

member Path : string



--------------------

new : unit -> AutoOpenAttribute

new : path:string -> AutoOpenAttribute

type unit = Unit

Multiple items

type MapSlim<'k,'v (requires equality and 'k :> IEquatable<'k>)> =

new : unit -> MapSlim<'k,'v>

new : capacity:int -> MapSlim<'k,'v>

val mutable private count: int

val mutable private entries: Entry<'k,'v> []

member private AddKey : key:'k * hashCode:int -> byref<'v>

member GetOption : key:'k -> 'v voption

member GetRef : key:'k -> byref<'v>

member GetRef : key:'k * added:outref<bool> -> byref<'v>

member Item : i:int -> 'k * 'v

member Key : i:int -> 'k

...



--------------------

new : unit -> MapSlim<'k,'v>

new : capacity:int -> MapSlim<'k,'v>

val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Multiple items

type CallerLineNumberAttribute =

inherit Attribute

new : unit -> CallerLineNumberAttribute



--------------------

CallerLineNumberAttribute() : CallerLineNumberAttribute

Multiple items

type OptionalAttribute =

inherit Attribute

new : unit -> OptionalAttribute



--------------------

OptionalAttribute() : OptionalAttribute

Multiple items

type DefaultParameterValueAttribute =

inherit Attribute

new : value:obj -> DefaultParameterValueAttribute

member Value : obj



--------------------

DefaultParameterValueAttribute(value: obj) : DefaultParameterValueAttribute

val lock : lockObject:'Lock -> action:(unit -> 'T) -> 'T (requires reference type)

val isNull : value:'T -> bool (requires 'T : null)

type IDisposable =

member Dispose : unit -> unit

Multiple items

val seq : sequence:seq<'T> -> seq<'T>



--------------------

type seq<'T> = Collections.Generic.IEnumerable<'T>

Multiple items

val float : value:'T -> float (requires member op_Explicit)



--------------------

type float = Double



--------------------

type float<'Measure> = float

Multiple items

module Result



from IRT



--------------------

module Result



from Microsoft.FSharp.Core



--------------------

[<Struct>]

type Result<'T,'TError> =

| Ok of ResultValue: 'T

| Error of ErrorValue: 'TError

val map : mapping:('T -> 'U) -> result:Result<'T,'TError> -> Result<'U,'TError>

val rev : list:'T list -> 'T list

val mapError : mapping:('TError -> 'U) -> result:Result<'T,'TError> -> Result<'T,'U>

String.Join(separator: string, values: Collections.Generic.IEnumerable<string>) : string

String.Join<'T>(separator: string, values: Collections.Generic.IEnumerable<'T>) : string

String.Join(separator: string, [<ParamArray>] values: obj []) : string

String.Join(separator: string, [<ParamArray>] value: string []) : string

String.Join(separator: string, value: string [], startIndex: int, count: int) : string

type IFormatProvider =

member GetFormat : formatType:Type -> obj

field NumberStyles.Any: NumberStyles = 511

Multiple items

type CultureInfo =

new : name:string -> CultureInfo + 3 overloads

member Calendar : Calendar

member ClearCachedData : unit -> unit

member Clone : unit -> obj

member CompareInfo : CompareInfo

member CultureTypes : CultureTypes

member DateTimeFormat : DateTimeFormatInfo with get, set

member DisplayName : string

member EnglishName : string

member Equals : value:obj -> bool

...



--------------------

CultureInfo(name: string) : CultureInfo

CultureInfo(culture: int) : CultureInfo

CultureInfo(name: string, useUserOverride: bool) : CultureInfo

CultureInfo(culture: int, useUserOverride: bool) : CultureInfo

property CultureInfo.InvariantCulture: CultureInfo

static member PCG.TryParse : s:string -> PCG option

val append : array1:'T [] -> array2:'T [] -> 'T []

val tryFind : predicate:('T -> bool) -> list:'T list -> 'T option

Multiple items

type StringBuilder =

new : unit -> StringBuilder + 5 overloads

member Append : value:string -> StringBuilder + 19 overloads

member AppendFormat : format:string * arg0:obj -> StringBuilder + 7 overloads

member AppendLine : unit -> StringBuilder + 1 overload

member Capacity : int with get, set

member Chars : int -> char with get, set

member Clear : unit -> StringBuilder

member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit

member EnsureCapacity : capacity:int -> int

member Equals : sb:StringBuilder -> bool

...



--------------------

Text.StringBuilder() : Text.StringBuilder

Text.StringBuilder(capacity: int) : Text.StringBuilder

Text.StringBuilder(value: string) : Text.StringBuilder

Text.StringBuilder(value: string, capacity: int) : Text.StringBuilder

Text.StringBuilder(capacity: int, maxCapacity: int) : Text.StringBuilder

Text.StringBuilder(value: string, startIndex: int, length: int, capacity: int) : Text.StringBuilder

val ignore : value:'T -> unit

module Seq



from Microsoft.FSharp.Collections

val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

val max : source:seq<'T> -> 'T (requires comparison)

val append : source1:seq<'T> -> source2:seq<'T> -> seq<'T>

val iter : action:('T -> unit) -> source:seq<'T> -> unit

val countBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'Key * int> (requires equality)

val choose : chooser:('T -> 'U option) -> source:seq<'T> -> seq<'U>

val toList : source:seq<'T> -> 'T list

val collect : mapping:('T -> 'U list) -> list:'T list -> 'U list

val isEmpty : list:'T list -> bool

val where : predicate:('T -> bool) -> list:'T list -> 'T list

val distinctBy : projection:('T -> 'Key) -> list:'T list -> 'T list (requires equality)

val toArray : list:'T list -> 'T []

val unzip : array:('T1 * 'T2) [] -> 'T1 [] * 'T2 []

val contains : value:'T -> source:'T list -> bool (requires equality)

val choose : chooser:('T -> 'U option) -> list:'T list -> 'U list

val sortInPlace : array:'T [] -> unit (requires comparison)

val sqrt : value:'T -> 'U (requires member Sqrt)

val reduce : reduction:('T -> 'T -> 'T) -> list:'T list -> 'T

type Console =

static member BackgroundColor : ConsoleColor with get, set

static member Beep : unit -> unit + 1 overload

static member BufferHeight : int with get, set

static member BufferWidth : int with get, set

static member CapsLock : bool

static member Clear : unit -> unit

static member CursorLeft : int with get, set

static member CursorSize : int with get, set

static member CursorTop : int with get, set

static member CursorVisible : bool with get, set

...

Console.WriteLine() : unit

(+0 other overloads)

Console.WriteLine(value: string) : unit

(+0 other overloads)

Console.WriteLine(value: obj) : unit

(+0 other overloads)

Console.WriteLine(value: uint64) : unit

(+0 other overloads)

Console.WriteLine(value: int64) : unit

(+0 other overloads)

Console.WriteLine(value: uint32) : unit

(+0 other overloads)

Console.WriteLine(value: int) : unit

(+0 other overloads)

Console.WriteLine(value: float32) : unit

(+0 other overloads)

Console.WriteLine(value: float) : unit

(+0 other overloads)

Console.WriteLine(value: decimal) : unit

(+0 other overloads)

event Console.CancelKeyPress: IEvent<ConsoleCancelEventHandler,ConsoleCancelEventArgs>

Multiple items

module Event



from Microsoft.FSharp.Control



--------------------

type Event<'T> =

new : unit -> Event<'T>

member Trigger : arg:'T -> unit

member Publish : IEvent<'T>



--------------------

type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =

new : unit -> Event<'Delegate,'Args>

member Trigger : sender:obj * args:'Args -> unit

member Publish : IEvent<'Delegate,'Args>



--------------------

new : unit -> Event<'T>



--------------------

new : unit -> Event<'Delegate,'Args>

val add : callback:('T -> unit) -> sourceEvent:IEvent<'Del,'T> -> unit (requires delegate and 'Del :> Delegate)

Console.Write(value: string) : unit

(+0 other overloads)

Console.Write(value: obj) : unit

(+0 other overloads)

Console.Write(value: uint64) : unit

(+0 other overloads)

Console.Write(value: int64) : unit

(+0 other overloads)

Console.Write(value: uint32) : unit

(+0 other overloads)

Console.Write(value: int) : unit

(+0 other overloads)

Console.Write(value: float32) : unit

(+0 other overloads)

Console.Write(value: decimal) : unit

(+0 other overloads)

Console.Write(value: float) : unit

(+0 other overloads)

Console.Write(buffer: char []) : unit

(+0 other overloads)

val length : list:'T list -> int

Multiple items

val ref : value:'T -> 'T ref



--------------------

type 'T ref = Ref<'T>

type Int64 =

struct

member CompareTo : value:obj -> int + 1 overload

member Equals : obj:obj -> bool + 1 overload

member GetHashCode : unit -> int

member GetTypeCode : unit -> TypeCode

member ToString : unit -> string + 3 overloads

static val MaxValue : int64

static val MinValue : int64

static member Parse : s:string -> int64 + 3 overloads

static member TryParse : s:string * result:int64 -> bool + 1 overload

end

field int64.MaxValue: int64 = 9223372036854775807L

type Interlocked =

static member Add : location1:int * value:int -> int + 1 overload

static member CompareExchange : location1:int * value:int * comparand:int -> int + 6 overloads

static member Decrement : location:int -> int + 1 overload

static member Exchange : location1:int * value:int -> int + 6 overloads

static member Increment : location:int -> int + 1 overload

static member MemoryBarrier : unit -> unit

static member Read : location:int64 -> int64

Interlocked.Increment(location: byref<int64>) : int64

Interlocked.Increment(location: byref<int>) : int

type ThreadPool =

static member BindHandle : osHandle:nativeint -> bool + 1 overload

static member GetAvailableThreads : workerThreads:int * completionPortThreads:int -> unit

static member GetMaxThreads : workerThreads:int * completionPortThreads:int -> unit

static member GetMinThreads : workerThreads:int * completionPortThreads:int -> unit

static member QueueUserWorkItem : callBack:WaitCallback -> bool + 1 overload

static member RegisterWaitForSingleObject : waitObject:WaitHandle * callBack:WaitOrTimerCallback * state:obj * millisecondsTimeOutInterval:uint32 * executeOnlyOnce:bool -> RegisteredWaitHandle + 3 overloads

static member SetMaxThreads : workerThreads:int * completionPortThreads:int -> bool

static member SetMinThreads : workerThreads:int * completionPortThreads:int -> bool

static member UnsafeQueueNativeOverlapped : overlapped:NativeOverlapped -> bool

static member UnsafeQueueUserWorkItem : callBack:WaitCallback * state:obj -> bool

...

ThreadPool.UnsafeQueueUserWorkItem(callBack: WaitCallback, state: obj) : bool

module Option



from Microsoft.FSharp.Core

val isNone : option:'T option -> bool

val set : array:'T [] -> index:int -> value:'T -> unit

val tryPick : chooser:('T -> 'U option) -> list:'T list -> 'U option

val pick : chooser:('T -> 'U option) -> list:'T list -> 'U

val defaultValue : value:'T -> option:'T option -> 'T

field Stopwatch.Frequency: int64

val defaultWith : defThunk:(unit -> 'T) -> option:'T option -> 'T

type Environment =

static member CommandLine : string

static member CurrentDirectory : string with get, set

static member CurrentManagedThreadId : int

static member Exit : exitCode:int -> unit

static member ExitCode : int with get, set

static member ExpandEnvironmentVariables : name:string -> string

static member FailFast : message:string -> unit + 1 overload

static member GetCommandLineArgs : unit -> string[]

static member GetEnvironmentVariable : variable:string -> string + 1 overload

static member GetEnvironmentVariables : unit -> IDictionary + 1 overload

...

nested type SpecialFolder

nested type SpecialFolderOption

Interlocked.Decrement(location: byref<int64>) : int64

Interlocked.Decrement(location: byref<int>) : int

val min : e1:'T -> e2:'T -> 'T (requires comparison)

val iteri : action:(int -> 'T -> unit) -> array:'T [] -> unit

val iter : action:('T -> unit) -> option:'T option -> unit

type GC =

static member AddMemoryPressure : bytesAllocated:int64 -> unit

static member CancelFullGCNotification : unit -> unit

static member Collect : unit -> unit + 4 overloads

static member CollectionCount : generation:int -> int

static member EndNoGCRegion : unit -> unit

static member GetGeneration : obj:obj -> int + 1 overload

static member GetTotalMemory : forceFullCollection:bool -> int64

static member KeepAlive : obj:obj -> unit

static member MaxGeneration : int

static member ReRegisterForFinalize : obj:obj -> unit

...

GC.GetTotalMemory(forceFullCollection: bool) : int64

Multiple items

type Thread =

inherit CriticalFinalizerObject

new : start:ThreadStart -> Thread + 3 overloads

member Abort : unit -> unit + 1 overload

member ApartmentState : ApartmentState with get, set

member CurrentCulture : CultureInfo with get, set

member CurrentUICulture : CultureInfo with get, set

member DisableComObjectEagerCleanup : unit -> unit

member ExecutionContext : ExecutionContext

member GetApartmentState : unit -> ApartmentState

member GetCompressedStack : unit -> CompressedStack

member GetHashCode : unit -> int

...



--------------------

Thread(start: ThreadStart) : Thread

Thread(start: ParameterizedThreadStart) : Thread

Thread(start: ThreadStart, maxStackSize: int) : Thread

Thread(start: ParameterizedThreadStart, maxStackSize: int) : Thread

Thread.Sleep(timeout: TimeSpan) : unit

Thread.Sleep(millisecondsTimeout: int) : unit

val max : e1:'T -> e2:'T -> 'T (requires comparison)

val iter : action:('T -> unit) -> list:'T list -> unit

Multiple items

val byte : value:'T -> byte (requires member op_Explicit)



--------------------

type byte = Byte

val defaultArg : arg:'T option -> defaultValue:'T -> 'T

field int.MaxValue: int = 2147483647

type BitConverter =

static val IsLittleEndian : bool

static member DoubleToInt64Bits : value:float -> int64

static member GetBytes : value:bool -> byte[] + 9 overloads

static member Int64BitsToDouble : value:int64 -> float

static member ToBoolean : value:byte[] * startIndex:int -> bool

static member ToChar : value:byte[] * startIndex:int -> char

static member ToDouble : value:byte[] * startIndex:int -> float

static member ToInt16 : value:byte[] * startIndex:int -> int16

static member ToInt32 : value:byte[] * startIndex:int -> int

static member ToInt64 : value:byte[] * startIndex:int -> int64

...

BitConverter.Int64BitsToDouble(value: int64) : float

type 'T array = 'T []

val toList : array:'T [] -> 'T list

val unzip : list:('T1 * 'T2) list -> 'T1 list * 'T2 list

val init : count:int -> initializer:(int -> 'T) -> seq<'T>

Multiple items

val char : value:'T -> char (requires member op_Explicit)



--------------------

type char = Char

module Operators



from Microsoft.FSharp.Core

val int : value:'T -> int (requires member op_Explicit)

val uint64 : value:'T -> uint64 (requires member op_Explicit)

Multiple items

type CompilationRepresentationAttribute =

inherit Attribute

new : flags:CompilationRepresentationFlags -> CompilationRepresentationAttribute

member Flags : CompilationRepresentationFlags



--------------------

new : flags:CompilationRepresentationFlags -> CompilationRepresentationAttribute

type CompilationRepresentationFlags =

| None = 0

| Static = 1

| Instance = 2

| ModuleSuffix = 4

| UseNullAsTrueValue = 8

| Event = 16

CompilationRepresentationFlags.ModuleSuffix: CompilationRepresentationFlags = 4

module Printf



from Microsoft.FSharp.Core

val kbprintf : continuation:(unit -> 'Result) -> builder:Text.StringBuilder -> format:Printf.BuilderFormat<'T,'Result> -> 'T

val box : value:'T -> obj

val exists : predicate:('T -> bool) -> array:'T [] -> bool

val fold2 : folder:('State -> 'T1 -> 'T2 -> 'State) -> state:'State -> array1:'T1 [] -> array2:'T2 [] -> 'State

val abs : value:'T -> 'T (requires member Abs)

val get : option:'T option -> 'T

val create : count:int -> value:'T -> 'T []

Multiple items

type Version =

new : unit -> Version + 4 overloads

member Build : int

member Clone : unit -> obj

member CompareTo : version:obj -> int + 1 overload

member Equals : obj:obj -> bool + 1 overload

member GetHashCode : unit -> int

member Major : int

member MajorRevision : int16

member Minor : int

member MinorRevision : int16

...



--------------------

Version() : Version

Version(version: string) : Version

Version(major: int, minor: int) : Version

Version(major: int, minor: int, build: int) : Version

Version(major: int, minor: int, build: int, revision: int) : Version

val defaultValueArg : arg:'T voption -> defaultValue:'T -> 'T

val dict : keyValuePairs:seq<'Key * 'Value> -> Collections.Generic.IDictionary<'Key,'Value> (requires equality)

val mapi : mapping:(int -> 'T -> 'U) -> array:'T [] -> 'U []

Multiple items

module Map



from Microsoft.FSharp.Collections



--------------------

type Map<'Key,'Value (requires comparison)> =

interface IReadOnlyDictionary<'Key,'Value>

interface IReadOnlyCollection<KeyValuePair<'Key,'Value>>

interface IEnumerable

interface IComparable

interface IEnumerable<KeyValuePair<'Key,'Value>>

interface ICollection<KeyValuePair<'Key,'Value>>

interface IDictionary<'Key,'Value>

new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>

member Add : key:'Key * value:'Value -> Map<'Key,'Value>

member ContainsKey : key:'Key -> bool

...



--------------------

new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>

val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)