Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Literate
namespace FSharp.Markdown
namespace System
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

Full name: Microsoft.FSharp.Core.EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
val main : args:string [] -> int

Full name: fsharp.main
val args : string []
val b : int

Full name: Fsharp.b
val mutable a : int

Full name: Fsharp.a
val c : int

Full name: Fsharp.c
val d : int
val v1 : int

Full name: Fsharp.v1
val v2 : char

Full name: Fsharp.v2
val add : x:int -> y:int -> int

Full name: Fsharp.add
val x : int
val y : int
val add' : (int -> int -> int)

Full name: Fsharp.add'
val add'' : x:int * y:int -> int

Full name: Fsharp.add''
val add1 : (int -> int)

Full name: Fsharp.add1
val ( x^2 ) : x:float -> float

Full name: Fsharp.( x^2 )
val x : float
val sqrt : _arg1:float -> float option

Full name: Fsharp.sqrt
type Double =
  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 MinValue : float
    static val MaxValue : float
    static val Epsilon : float
    static val NegativeInfinity : float
    static val PositiveInfinity : float
    ...
  end

Full name: System.Double
Double.IsNaN(d: float) : bool
Double.IsInfinity(d: float) : bool
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
type Math =
  static val PI : float
  static val E : float
  static member Abs : value:sbyte -> sbyte + 6 overloads
  static member Acos : d:float -> float
  static member Asin : d:float -> float
  static member Atan : d:float -> float
  static member Atan2 : y:float * x:float -> float
  static member BigMul : a:int * b:int -> int64
  static member Ceiling : d:decimal -> decimal + 1 overload
  static member Cos : d:float -> float
  ...

Full name: System.Math
Math.Sqrt(d: float) : float
val mult : x:int -> y:int -> int

Full name: Fsharp.mult
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val mult' : x:int -> y:int -> int

Full name: Fsharp.mult'
val add : a:int -> b:int -> int

Full name: Fsharp.add
val a : int
val b : int
val add' : a:'a -> b:'b -> 'c (requires member ( + ))

Full name: Fsharp.add'
val a : 'a (requires member ( + ))
val b : 'b (requires member ( + ))
val succ' : x:int -> int

Full name: Fsharp.succ'
module LanguagePrimitives

from Microsoft.FSharp.Core
val GenericOne<'T (requires member get_One)> : 'T (requires member get_One)

Full name: Microsoft.FSharp.Core.LanguagePrimitives.GenericOne
val succ : x:'a -> 'c (requires member ( + ) and member get_One)

Full name: Fsharp.succ
val x : 'a (requires member ( + ) and member get_One)
val fibonacci : _arg1:int -> int

Full name: Fsharp.fibonacci
val n : int
val squared : x:int -> int

Full name: Fsharp.squared
val addTwo : x:int -> int

Full name: Fsharp.addTwo
val squareThenAdd : (int -> int)

Full name: Fsharp.squareThenAdd
val addThenSquare : (int -> int)

Full name: Fsharp.addThenSquare
val squareThenAdd' : (int -> int)

Full name: Fsharp.squareThenAdd'
val addThenSquare' : (int -> int)

Full name: Fsharp.addThenSquare'
type Foo =
  static member Bar : ?c:int -> int

Full name: Fsharp.Foo
static member Foo.Bar : ?c:int -> int

Full name: Fsharp.Foo.Bar
val c : int option
val c : int
val defaultArg : arg:'T option -> defaultValue:'T -> 'T

Full name: Microsoft.FSharp.Core.Operators.defaultArg
val t : float * string

Full name: Fsharp.t
val f : float

Full name: Fsharp.f
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val s : string

Full name: Fsharp.s
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val t' : float * string * (int * DateTime)

Full name: Fsharp.t'
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
DateTime()
   (+0 other overloads)
DateTime(ticks: int64) : unit
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
   (+0 other overloads)
property DateTime.UtcNow: DateTime
val f' : float

Full name: Fsharp.f'
val s' : string

Full name: Fsharp.s'
val i : int

Full name: Fsharp.i
val d : DateTime

Full name: Fsharp.d
val f'' : float

Full name: Fsharp.f''
val s'' : string

Full name: Fsharp.s''
val c' : int * DateTime

Full name: Fsharp.c'
val mutable out : int

Full name: Fsharp.out
val success : bool

Full name: Fsharp.success
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

Full name: System.Int32
Int32.TryParse(s: string, result: byref<int>) : bool
Int32.TryParse(s: string, style: Globalization.NumberStyles, provider: IFormatProvider, result: byref<int>) : bool
val success' : bool

Full name: Fsharp.success'
val out' : int

Full name: Fsharp.out'
val i : int
type Record =
  {F1: string;
   F2: int;}

Full name: Fsharp.Record
Record.F1: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
Record.F2: int
type Person =
  {FirstName: string;
   LastName: string;
   DoB: DateTime;
   DoD: DateTime option;}

Full name: Fsharp.Person
Person.FirstName: string
Person.LastName: string
Person.DoB: DateTime
Person.DoD: DateTime option
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
val wolfgang : Person

Full name: Fsharp.wolfgang
val bizet : Person

Full name: Fsharp.bizet
property DateTime.Year: int
val passedAwayWolfgang : Person

Full name: Fsharp.passedAwayWolfgang
type DU =
  | Case1
  | Case2 of string
  | Case3 of int * int
  | Case4 of x: float * y: float
  | Case5 of inception: DU * DateTime

Full name: Fsharp.DU
union case DU.Case1: DU
union case DU.Case2: string -> DU
union case DU.Case3: int * int -> DU
union case DU.Case4: x: float * y: float -> DU
argument x : float
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
argument y : float
union case DU.Case5: inception: DU * DateTime -> DU
type SingleCase = | SC of string

Full name: Fsharp.SingleCase
union case SingleCase.SC: string -> SingleCase
type SingleGen<'a> = | C of 'a

Full name: Fsharp.SingleGen<_>
union case SingleGen.C: 'a -> SingleGen<'a>
type Opt<'a> =
  | Nothing
  | Something of 'a

Full name: Fsharp.Opt<_>
union case Opt.Nothing: Opt<'a>
union case Opt.Something: 'a -> Opt<'a>
val opt : int option

Full name: Fsharp.opt
module Option

from Microsoft.FSharp.Core
val isNone : option:'T option -> bool

Full name: Microsoft.FSharp.Core.Option.isNone
val get : option:'T option -> 'T

Full name: Microsoft.FSharp.Core.Option.get
type BinTree<'a> =
  | Node of left: BinTree<'a> * value: 'a * right: BinTree<'a>
  | Leaf of value: 'a
  member InOrder : seq<'a>

Full name: Fsharp.BinTree<_>
union case BinTree.Node: left: BinTree<'a> * value: 'a * right: BinTree<'a> -> BinTree<'a>
union case BinTree.Leaf: value: 'a -> BinTree<'a>
val tree : BinTree<'a>
member BinTree.InOrder : seq<'a>

Full name: Fsharp.BinTree`1.InOrder
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

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

Full name: Microsoft.FSharp.Collections.seq<_>
val value : 'a
val l : BinTree<'a>
val v : 'a
val r : BinTree<'a>
property BinTree.InOrder: seq<'a>
val tree : BinTree<string>

Full name: Fsharp.tree
val flattened : string list

Full name: Fsharp.flattened
property BinTree.InOrder: seq<string>
module Seq

from Microsoft.FSharp.Collections
val toList : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.Seq.toList
val foo : string

Full name: Fsharp.foo
type obj = Object

Full name: Microsoft.FSharp.Core.obj
Multiple items
type NoEqualityAttribute =
  inherit Attribute
  new : unit -> NoEqualityAttribute

Full name: Microsoft.FSharp.Core.NoEqualityAttribute

--------------------
new : unit -> NoEqualityAttribute
Multiple items
type NoComparisonAttribute =
  inherit Attribute
  new : unit -> NoComparisonAttribute

Full name: Microsoft.FSharp.Core.NoComparisonAttribute

--------------------
new : unit -> NoComparisonAttribute
type CanNotCompare<'a> = | CNC of 'a

Full name: Fsharp.CanNotCompare<_>
union case CanNotCompare.CNC: 'a -> CanNotCompare<'a>
val toA : unit -> string

Full name: Fsharp.toA
val toB : unit -> string

Full name: Fsharp.toB
val x : int list

Full name: Fsharp.x
val y : int list

Full name: Fsharp.y
val evenSquares : (int * int) list

Full name: Fsharp.evenSquares
val evenSquares' : (int * int) list

Full name: Fsharp.evenSquares'
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  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
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
Object.ReferenceEquals(objA: obj, objB: obj) : bool
val tail : list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.tail
val notThatMuch : seq<'a>

Full name: Fsharp.notThatMuch
val empty<'T> : seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.empty
val range : seq<int>

Full name: Fsharp.range
val height : int

Full name: Fsharp.height
val width : int

Full name: Fsharp.width
val row : int
val col : int
val fib : seq<obj>

Full name: Fsharp.fib
val unfold : generator:('State -> ('T * 'State) option) -> state:'State -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.unfold
val n1 : obj
val n2 : obj
val item : index:int -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.item
val arr : int []

Full name: Fsharp.arr
Multiple items
type ArgumentException =
  inherit SystemException
  new : unit -> ArgumentException + 4 overloads
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Message : string
  member ParamName : string

Full name: System.ArgumentException

--------------------
ArgumentException() : unit
ArgumentException(message: string) : unit
ArgumentException(message: string, innerException: exn) : unit
ArgumentException(message: string, paramName: string) : unit
ArgumentException(message: string, paramName: string, innerException: exn) : unit
val ex : ArgumentException
property ArgumentException.Message: string
Multiple items
type InvalidOperationException =
  inherit SystemException
  new : unit -> InvalidOperationException + 2 overloads

Full name: System.InvalidOperationException

--------------------
InvalidOperationException() : unit
InvalidOperationException(message: string) : unit
InvalidOperationException(message: string, innerException: exn) : unit
val ex : exn
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
property Exception.Message: string
val z : int
val xs : int list
val e : float
val greet : _arg1:Person -> string

Full name: Fsharp.greet
val ln : string
val d : DateTime
val fn : string
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
Multiple items
val double : value:'T -> double (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.double

--------------------
type double = Double

Full name: Microsoft.FSharp.Core.double
val d : double
active recognizer Even: int -> Choice<unit,unit>

Full name: Fsharp.( |Even|Odd| )
active recognizer Odd: int -> Choice<unit,unit>

Full name: Fsharp.( |Even|Odd| )
val color : Drawing.Color
namespace System.Drawing
type Color =
  struct
    member A : byte
    member B : byte
    member Equals : obj:obj -> bool
    member G : byte
    member GetBrightness : unit -> float32
    member GetHashCode : unit -> int
    member GetHue : unit -> float32
    member GetSaturation : unit -> float32
    member IsEmpty : bool
    member IsKnownColor : bool
    ...
  end

Full name: System.Drawing.Color
property Drawing.Color.R: byte
property Drawing.Color.G: byte
property Drawing.Color.B: byte
val printRGB : _arg1:Drawing.Color -> unit

Full name: Fsharp.printRGB
active recognizer RGB: Drawing.Color -> byte * byte * byte

Full name: Fsharp.( |RGB| )
val r : byte
val g : byte
val b : byte
val printf : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printf
val input : string
namespace System.Text
namespace System.Text.RegularExpressions
val regex : string
val m : Match
Multiple items
type Regex =
  new : pattern:string -> Regex + 2 overloads
  member GetGroupNames : unit -> string[]
  member GetGroupNumbers : unit -> int[]
  member GroupNameFromNumber : i:int -> string
  member GroupNumberFromName : name:string -> int
  member IsMatch : input:string -> bool + 1 overload
  member Match : input:string -> Match + 2 overloads
  member MatchTimeout : TimeSpan
  member Matches : input:string -> MatchCollection + 1 overload
  member Options : RegexOptions
  ...

Full name: System.Text.RegularExpressions.Regex

--------------------
Regex(pattern: string) : unit
Regex(pattern: string, options: RegexOptions) : unit
Regex(pattern: string, options: RegexOptions, matchTimeout: TimeSpan) : unit
type Match =
  inherit Group
  member Groups : GroupCollection
  member NextMatch : unit -> Match
  member Result : replacement:string -> string
  static member Empty : Match
  static member Synchronized : inner:Match -> Match

Full name: System.Text.RegularExpressions.Match
property Group.Success: bool
val g : Group
property Match.Groups: GroupCollection
property Capture.Value: string
active recognizer Integer: string -> int option

Full name: Fsharp.( |Integer|_| )
active recognizer Parse: string -> string -> string list option

Full name: Fsharp.( |Parse|_| )
val m : int
val s : string
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

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

Full name: Microsoft.FSharp.Collections.seq<_>
type exn = System.Exception

Full name: Microsoft.FSharp.Core.exn
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
namespace System.Threading
val res : Choice<string,exn>

Full name: Fsharp.res
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val u : Uri
Multiple items
type Uri =
  new : uriString:string -> Uri + 5 overloads
  member AbsolutePath : string
  member AbsoluteUri : string
  member Authority : string
  member DnsSafeHost : string
  member Equals : comparand:obj -> bool
  member Fragment : string
  member GetComponents : components:UriComponents * format:UriFormat -> string
  member GetHashCode : unit -> int
  member GetLeftPart : part:UriPartial -> string
  ...

Full name: System.Uri

--------------------
Uri(uriString: string) : unit
Uri(uriString: string, uriKind: UriKind) : unit
Uri(baseUri: Uri, relativeUri: string) : unit
Uri(baseUri: Uri, relativeUri: Uri) : unit
val ctx : SynchronizationContext
Multiple items
type SynchronizationContext =
  new : unit -> SynchronizationContext
  member CreateCopy : unit -> SynchronizationContext
  member IsWaitNotificationRequired : unit -> bool
  member OperationCompleted : unit -> unit
  member OperationStarted : unit -> unit
  member Post : d:SendOrPostCallback * state:obj -> unit
  member Send : d:SendOrPostCallback * state:obj -> unit
  member Wait : waitHandles:nativeint[] * waitAll:bool * millisecondsTimeout:int -> int
  static member Current : SynchronizationContext
  static member SetSynchronizationContext : syncContext:SynchronizationContext -> unit

Full name: System.Threading.SynchronizationContext

--------------------
SynchronizationContext() : unit
property SynchronizationContext.Current: SynchronizationContext
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.SwitchToThreadPool : unit -> Async<unit>
val client : Net.WebClient
namespace System.Net
Multiple items
type WebClient =
  inherit Component
  new : unit -> WebClient
  member AllowReadStreamBuffering : bool with get, set
  member AllowWriteStreamBuffering : bool with get, set
  member BaseAddress : string with get, set
  member CachePolicy : RequestCachePolicy with get, set
  member CancelAsync : unit -> unit
  member Credentials : ICredentials with get, set
  member DownloadData : address:string -> byte[] + 1 overload
  member DownloadDataAsync : address:Uri -> unit + 1 overload
  member DownloadDataTaskAsync : address:string -> Task<byte[]> + 1 overload
  ...

Full name: System.Net.WebClient

--------------------
Net.WebClient() : unit
val b : byte []
member Net.WebClient.AsyncDownloadData : address:Uri -> Async<byte []>
type Encoding =
  member BodyName : string
  member Clone : unit -> obj
  member CodePage : int
  member DecoderFallback : DecoderFallback with get, set
  member EncoderFallback : EncoderFallback with get, set
  member EncodingName : string
  member Equals : value:obj -> bool
  member GetByteCount : chars:char[] -> int + 3 overloads
  member GetBytes : chars:char[] -> byte[] + 5 overloads
  member GetCharCount : bytes:byte[] -> int + 2 overloads
  ...

Full name: System.Text.Encoding
property Text.Encoding.UTF8: Text.Encoding
Text.Encoding.GetString(bytes: byte []) : string
Text.Encoding.GetString(bytes: nativeptr<byte>, byteCount: int) : string
Text.Encoding.GetString(bytes: byte [], index: int, count: int) : string
static member Async.SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member Async.Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val r : string
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
Multiple items
val exn : exn

--------------------
type exn = Exception

Full name: Microsoft.FSharp.Core.exn
namespace FSharp.Configuration
Multiple items
type Config =
  inherit Root
  new : unit -> Config
  event Changed : EventHandler
  member Error : IEvent<Exception>
  member Meetup : Meetup_Type
  nested type Meetup_Type

Full name: Fsharp.Config

--------------------
Config() : Config
type YamlConfig =
  inherit Root
  member Error : IEvent<Exception>

Full name: FSharp.Configuration.YamlConfig


<summary>Statically typed YAML config.</summary>
           <param name='FilePath'>Path to YAML file.</param>
           <param name='ReadOnly'>Whether the resulting properties will be read-only or not.</param>
           <param name='YamlText'>Yaml as text. Mutually exclusive with FilePath parameter.</param>
val config : Config.Meetup_Type

Full name: Fsharp.config
property Config.Meetup_Type.topic: string
property Config.Meetup_Type.duration: int
Multiple items
namespace FSharp.Data

--------------------
namespace Microsoft.FSharp.Data
type Message = XmlProvider<...>

Full name: Fsharp.Message
type XmlProvider

Full name: FSharp.Data.XmlProvider


<summary>Typed representation of a XML file.</summary>
       <param name='Sample'>Location of a XML sample file or a string containing a sample XML document.</param>
       <param name='SampleIsList'>If true, the children of the root in the sample document represent individual samples for the inference.</param>
       <param name='Global'>If true, the inference unifies all XML elements with the same name.</param>
       <param name='Culture'>The culture used for parsing numbers and dates. Defaults to the invariant culture.</param>
       <param name='Encoding'>The encoding used to read the sample. You can specify either the character set name or the codepage number. Defaults to UTF8 for files, and to ISO-8859-1 the for HTTP requests, unless `charset` is specified in the `Content-Type` response header.</param>
       <param name='ResolutionFolder'>A directory that is used when resolving relative file references (at design time and in hosted execution).</param>
       <param name='EmbeddedResource'>When specified, the type provider first attempts to load the sample from the specified resource
          (e.g. 'MyCompany.MyAssembly, resource_name.xml'). This is useful when exposing types generated by the type provider.</param>
       <param name='InferTypesFromValues'>If true, turns on additional type inference from values.
          (e.g. type inference infers string values such as "123" as ints and values constrained to 0 and 1 as booleans. The XmlProvider also infers string values as JSON.)</param>
val xml : XmlProvider<...>.Message

Full name: Fsharp.xml
XmlProvider<...>.Load(uri: string) : XmlProvider<...>.Message


Loads XML from the specified uri

XmlProvider<...>.Load(reader: IO.TextReader) : XmlProvider<...>.Message


Loads XML from the specified reader

XmlProvider<...>.Load(stream: IO.Stream) : XmlProvider<...>.Message


Loads XML from the specified stream
property XmlProvider<...>.Message.Available: Option<string>
val nil : XmlProvider<...>.Nil

Full name: Fsharp.nil
type Nil =
  inherit XmlElement
  new : nil: Option<bool> * value: Option<decimal> -> Nil + 1 overload
  member Nil : Option<bool>
  member Value : Option<decimal>

Full name: FSharp.Data.XmlProvider,Sample="sampleMessages.xml",SampleIsList="True".Nil
property XmlProvider<...>.Message.Nil: XmlProvider<...>.Nil
property XmlProvider<...>.Nil.Nil: Option<bool>
type bool = Boolean

Full name: Microsoft.FSharp.Core.bool
property XmlProvider<...>.Nil.Value: Option<decimal>
Multiple items
val decimal : value:'T -> decimal (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.decimal

--------------------
type decimal = Decimal

Full name: Microsoft.FSharp.Core.decimal

--------------------
type decimal<'Measure> = decimal

Full name: Microsoft.FSharp.Core.decimal<_>
property XmlProvider<...>.Message.Missing: Option<string>
val missingNil : XmlProvider<...>.MissingNil option

Full name: Fsharp.missingNil
type MissingNil =
  inherit XmlElement
  new : nil: Option<bool> * value: Option<int> -> MissingNil + 1 overload
  member Nil : Option<bool>
  member Value : Option<int>

Full name: FSharp.Data.XmlProvider,Sample="sampleMessages.xml",SampleIsList="True".MissingNil
property XmlProvider<...>.Message.MissingNil: Option<XmlProvider<...>.MissingNil>
val map : mapping:('T -> 'U) -> option:'T option -> 'U option

Full name: Microsoft.FSharp.Core.Option.map
val mn : XmlProvider<...>.MissingNil
property XmlProvider<...>.MissingNil.Nil: Option<bool>
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
property XmlProvider<...>.MissingNil.Value: Option<int>
Multiple items
type MeasureAttribute =
  inherit Attribute
  new : unit -> MeasureAttribute

Full name: Microsoft.FSharp.Core.MeasureAttribute

--------------------
new : unit -> MeasureAttribute
[<Measure>]
type s

Full name: Fsharp.s
[<Measure>]
type ms =
  static member perSecond : float<ms/s>

Full name: Fsharp.ms
static member ms.perSecond : float<ms/s>

Full name: Fsharp.ms.perSecond
val timeout : float<s>

Full name: Fsharp.timeout
property ms.perSecond: float<ms/s>
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Data
namespace Microsoft.FSharp.Data.UnitSystems
namespace Microsoft.FSharp.Data.UnitSystems.SI
namespace Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols
val distance : float<m>

Full name: Fsharp.Symbols.distance
[<Measure>]
type m = UnitSystems.SI.UnitNames.metre

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.m
val time : float<s>

Full name: Fsharp.Symbols.time
[<Measure>]
type s = UnitSystems.SI.UnitNames.second

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.s
val speed : float<m/s>

Full name: Fsharp.Symbols.speed
val acceleration : float<m/s ^ 2>

Full name: Fsharp.Symbols.acceleration
val mass : float<kg>

Full name: Fsharp.Symbols.mass
[<Measure>]
type kg = UnitSystems.SI.UnitNames.kilogram

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.kg
val force : float<N>

Full name: Fsharp.Symbols.force
[<Measure>]
type N = UnitSystems.SI.UnitNames.newton

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols.N
namespace Microsoft.FSharp.Data.UnitSystems.SI.UnitNames
val distance : float<metre>

Full name: Fsharp.Names.distance
[<Measure>]
type metre

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitNames.metre
val time : float<second>

Full name: Fsharp.Names.time
[<Measure>]
type second

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitNames.second
val speed : float<metre/second>

Full name: Fsharp.Names.speed
val acceleration : float<metre/second ^ 2>

Full name: Fsharp.Names.acceleration
val mass : float<kilogram>

Full name: Fsharp.Names.mass
[<Measure>]
type kilogram

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitNames.kilogram
val force : float<newton>

Full name: Fsharp.Names.force
[<Measure>]
type newton = kilogram metre/second ^ 2

Full name: Microsoft.FSharp.Data.UnitSystems.SI.UnitNames.newton
type FxRate<'u,'v> =
  {Rate: float<'u/'v>;
   Date: DateTime;}

Full name: Fsharp.FxRate<_,_>
FxRate.Rate: float<'u/'v>
FxRate.Date: DateTime
[<Measure>]
type CHF

Full name: Fsharp.CHF
[<Measure>]
type GBP

Full name: Fsharp.GBP
val gbp : FxRate<GBP,CHF> list

Full name: Fsharp.gbp
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val op : a:'T1 -> b:'T2 -> 'T3 (requires member ( ? ))

Full name: Fsharp.op
val a : 'T1 (requires member ( ? ))
val b : 'T2
val div : a:'a -> b:'b -> '_arg3 (requires member ( %% ))

Full name: Fsharp.div
val a : 'a (requires member ( %% ))
val b : 'b (requires member ( %% ))
val x : 'a (requires member ( + ) and member ( % ))
val y : 'c (requires member ( % ) and member ( + ))
val optionOfNillable : n:'N -> 'T option (requires member get_Nil and member get_Value)

Full name: Fsharp.optionOfNillable
val n : 'N (requires member get_Nil and member get_Value)
val nil' : decimal option

Full name: Fsharp.nil'
val missingNil' : int option

Full name: Fsharp.missingNil'
val bind : binder:('T -> 'U option) -> option:'T option -> 'U option

Full name: Microsoft.FSharp.Core.Option.bind
namespace System.Runtime
namespace System.Runtime.InteropServices
Multiple items
type CompiledNameAttribute =
  inherit Attribute
  new : compiledName:string -> CompiledNameAttribute
  member CompiledName : string

Full name: Microsoft.FSharp.Core.CompiledNameAttribute

--------------------
new : compiledName:string -> CompiledNameAttribute
static member Foo C#.Bar : ?c:int -> int

Full name: Fsharp.Foo C#.Bar
Multiple items
type OptionalAttribute =
  inherit Attribute
  new : unit -> OptionalAttribute

Full name: System.Runtime.InteropServices.OptionalAttribute

--------------------
OptionalAttribute() : unit
Multiple items
type DefaultParameterValueAttribute =
  inherit Attribute
  new : value:obj -> DefaultParameterValueAttribute
  member Value : obj

Full name: System.Runtime.InteropServices.DefaultParameterValueAttribute

--------------------
DefaultParameterValueAttribute(value: obj) : unit

Introduction to

F#

Today's menu

Some rules

  • Ask questions whenever you want
    • Non-general interest issues will be postponed
  • This presentation is hierarchical
    • We'll go through at least once
  • Your brain will hurt
    • even though it's just a fragment
    • you won't understand half of it
      • this is my fault
    • pain turns into happiness
      • takes perseverance

Prerequisites

  • VS >= 2019

or

  • Visual Studio Code
  • Ionide-fsharp

or

  • Rider

or

  • ...

What

  • open source
  • cross-platform
  • functional first
    • Functions as first class "objects"
    • Functions of Functions returning Functions
  • Pure Data
  • everything is an expression
  • variables, loops, traditional objects, state, side effects
  • order of things matters
  • indentation matters
  • + (almost) all of .NET

Why 1/3

FP is easier to write, easier to read, easier to test, and easier to understand. [...] you have found it anything but easy. All those [...] are anything but easy. [...] But that’s just a problem with familiarity. Once you are familiar with those concepts – and it doesn’t take long to develop that familiarity – programming gets a lot easier.

This means that the programmer has to juggle fewer balls in the air at the same time. There’s less to remember. Less to keep track of. And therefore the code is much simpler to write, read, understand, and test. [...]

The bottom line is this: Functional programming is important. You should learn it.

Uncle Bob

Why 2/3

We built all of these features because we think that they are better than the previous alternative. [...]

We are a big believer in enabling the use of fewer lines, fewer characters to specify a given concept or operation, and the reducing needless repetition. That’s what most of these new features enable.

Nullable differs in that it results in more reliable code. Every app or library that uses nullable is less likely to crash in production.

Software is too complicated for human minds to see the mistakes that a compiler can.

A common theme across these features is that they reduce noise and increase signal when you are looking at your code in a code editor. More important aspects should now pop.

The C# design team announcing .NET 6

Why 3/3

Correctness : no state, no null, less exceptions, strong type system

Conciseness : less noise, pattern matching

Concurrency : natural async, message queueing and reactive programming, immutability by default, no side-effects

Convenience, Productivity, : data processing, complex type definitions, type providers, compiler generated equality / comparison

Hello world

1: 
printfn "Hello, world!"
Hello, world!
1: 
2: 
3: 
4: 
[<EntryPoint>]
let main args =
    printfn "Hello, %s" args.[0]
    0

Bindings

1: 
2: 
let b = 3               // val b : int = 3
b = 4                   // val it : bool = false
1: 
2: 
let mutable a = 1       // val mutable a : int = 1
a <- 2                  // val it : unit = ()
1: 
2: 
3: 
let c =
    let d = 2
    d + d               // val c : int = 4
1: 
let v1, v2 = 42, 'f'

Functions

1: 
2: 
3: 
4: 
let add x y = x + y     // val add : x:int -> y:int -> int
let add' = (+)          // val add' : (int -> int -> int)
let add''(x, y) = x + y // val add'' : x:int * y:int -> int
let add1 = add 1        // val add1 : (int -> int)               
1: 
2: 
let ``x^2`` =
    fun x -> x ** 2.0                                            
1: 
2: 
3: 
4: 
5: 
6: 
7: 
let sqrt = function     // val sqrt : _arg1:float -> float option
| x when
    x < 0.0 ||
    x |> Double.IsNaN ||
    x |> Double.IsInfinity
    -> None
| x -> Some <| Math.Sqrt x

Type annotations

In general: x(x : tpe)

1: 
2: 
let mult (x : int) (y : int) : int =
    ((x : int) * (y : int) : int)

Then leave out superfluous parentheses:

1: 
2: 
let mult' (x : int) (y : int) : int =
    (x : int) * (y : int) : int

Automatic generalization

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let add a b = a + b
// val add : a: int -> b : int -> int

let inline add' a b = a + b
// val inline add' :
//   a: ^a -> b: ^b ->  ^c
//     when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let succ' x = x + LanguagePrimitives.GenericOne
// val succ' : x:int -> int

let inline succ x = x + LanguagePrimitives.GenericOne
// val inline succ :
//   x: ^a ->  ^c
//     when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c) and
//           ^b : (static member get_One : ->  ^b)

Recursion naive

1: 
2: 
3: 
4: 
5: 
6: 
let rec fibonacci = function
| 0 -> 0
| 1 -> 1
| n -> fibonacci(n-1) + fibonacci(n-2)

fibonacci 6             // val it : int = 8

Composition

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
let squared x = x * x
let addTwo x = x + 2

let squareThenAdd = squared >> addTwo   // (f >> g) x ≡ (g ∘ f)(x) ≡ g(f(x))
let addThenSquare = addTwo >> squared

let squareThenAdd' = addTwo << squared  // (f << g) x ≡ (f ∘ g)(x) ≡ f(g(x))
let addThenSquare' = squared << addTwo

squareThenAdd 3     // val it : int = 11
addThenSquare 3     // val it : int = 25
squareThenAdd' 3    // val it : int = 11
addThenSquare' 3    // val it : int = 25

Functions vs. Methods

Function Method
powerful type inference more easily discoverable
higher order functions may reduce parameter list length
no hidden dependency overloading *

curried vs. tupled

Curried Tupled
partial application named parameters
function composition, pipes optional parameters
less noise overloading *
"legacy" .NET interaction

Optional parameters and shadowing

1: 
2: 
3: 
4: 
type Foo =
    static member Bar(?c) =
        let c = defaultArg c 1                // val c : int option
        42 * c

Tuples

1: 
2: 
3: 
let t = (1.0, "Foo")    // val t : float * string
let f = fst t
let s = snd t
1: 
2: 
3: 
let t' = (1.0, "Foo", (2, DateTime.UtcNow))
let (f', s', (i, d)) = t'
let (f'', s'', c') = t'
1: 
()                      // val it : unit = ()

x.TryParse

1: 
2: 
let mutable out = 0
let success = Int32.TryParse("3.141", &out)
1: 
2: 
3: 
4: 
5: 
let success', out' = Int32.TryParse "3.141"

match Int32.TryParse "3.141" with
| true, i -> printfn "%i" i
| _ -> printfn "Failed" 

Record types

Declaration

1: 
type Record = { F1 : string; F2 : int }
1: 
2: 
3: 
4: 
5: 
type Person = {
    FirstName : string
    LastName : string
    DoB : DateTime
    DoD : DateTime option }

Instantiation

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let wolfgang = {
    FirstName = "W.A."
    LastName = "Mozart"
    DoB = DateTime(1756, 1, 27)
    DoD = None }

let bizet = {
    FirstName = "Georges"
    LastName = "Bizet"
    DoB = DateTime(1838, 10, 25)
    DoD = None }

C#

1: 
2: 
var mozart =
    new Person("W.A.", "Mozart", new DateTime(1756, 1, 27))

Read

1: 
printfn "%s was born in %i" bizet.FirstName bizet.DoB.Year

Update

1: 
2: 
let passedAwayWolfgang =
    { wolfgang with DoD = DateTime(1791, 12, 5) |> Some }

Discriminated Unions

1: 
2: 
3: 
4: 
5: 
6: 
type DU =
| Case1
| Case2 of string
| Case3 of int * int
| Case4 of x : float * y : float
| Case5 of inception : DU * DateTime
1: 
2: 
type SingleCase = SC of string
type SingleGen<'a> = C of 'a

You can not have a value of type of a case:

1: 
2: 
// let invalid (c : Case1) = ()
//                  ^^^^^ the type 'Case1' is not defined

Option

1: 
2: 
3: 
4: 
5: 
type Opt<'a> =
| Nothing
| Something of 'a
// with
//     ...
1: 
2: 
3: 
4: 
5: 
6: 
let opt = Some 12

if opt |> Option.isNone then
    0
else
    opt |> Option.get

BinaryTree

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
type BinTree<'a> =
| Node of
    left : BinTree<'a> * value : 'a * right : BinTree<'a>
| Leaf of value : 'a
with
    member tree.InOrder = seq {
        match tree with
        | Leaf value -> yield value
        | Node (l, v, r) ->
            yield! l.InOrder
            yield v
            yield! r.InOrder }

let tree =
    Node(Leaf "A", "B", Node(Leaf "C", "D", Leaf "E"))

let flattened = tree.InOrder |> Seq.toList
["A"; "B"; "C"; "D"; "E"]

C#

1: 
2: 
3: 
4: 
var tree = new Node(
    new Leaf("A"),
    "B",
    new Node(new Leaf("C"), "D", new Leaf("E")))               
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
public static IEnumerable<T> InOrder<T>(this BinTree<T> tree)
{
    switch (tree.Tag)
    {
        case BinTree<T>.Tags.Leaf:
            yield return ((BinTree<T>.Leaf)tree).value;
            break;
        case BinTree<T>.Tags.Node:
            var node = (BinTree<T>.Node)tree;
            foreach (var l in node.left.InOrder()) {
                yield return l;
            }
            yield return node.value;
            foreach (var r in node.right.InOrder()) {
                yield return r;
            }
            break;
            // ...
1: 
2: 
3: 
4: 
5: 
        // ...
        default:
            throw new Exception("Never happens... Right?");
    }
}

For free:

1: 
tree.IsLeaf, tree.IsNode

Equality

1: 
2: 
3: 
4: 
let foo = "Foo"
(=)                                                  // val it : bool = true
    { FirstName = "Foo"; LastName = "Bar"; DoB = DateTime(0L); DoD = None }
    { FirstName = foo; LastName = "Bar"; DoB = new DateTime(0L); DoD = None }
1: 
2: 
Some 12 = Some 12                                    // val it : bool = true
Some(obj()) = Some(obj())                            // val it : bool = false

NoEquality

1: 
2: 
3: 
4: 
5: 
[<NoEquality; NoComparison>]
type CanNotCompare<'a> = CNC of 'a

// CNC 12 = CNC 33
// ^^^^^^

error FS0001: The type 'CanNotCompare<'a>' does not support the 'equality' constraint because it has the 'NoEquality' attribute

Further customization

  • StructuralEquality
    records, tuples, DUs, F# container classes

  • ReferenceEquality
    everything else

  • CustomEquality
    Equals(o : obj), Equals(t : T), GetHashCode(), IEquatable

  • NoEquality
    F# only, safe choice for e.g. functions

  • EqualityConditionalOn
    Equality support depends on generic argument(s)

Comparison

1: 
2: 
Some 3 > Some 2       // val it : bool = true
None <= Some 1        // val it : bool = true
1: 
2: 
3: 
4: 
let toA = fun () -> "A"
let toB = fun () -> "B"
// Some(toA) <= Some(toB)
//      ^^^

error FS0001: The type '(unit -> string)' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface

Further customization

  • StructuralComparison
    records, tuples, DUs

  • CustomComparison
    IComparable, CompareTo(o)

  • NoComparison
    good choice for most types

  • ComparisonConditionalOn
    comparison support depends on generic argument(s)

Lists

1: 
2: 
let x = 3 :: [1; 4] @ [1; 5; 9]    // val x : int list = [3;1;4;1;5;9]    
let y = [1 .. 2 .. 5]              // val y : int list = [1;3;5]
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let evenSquares =                  // val evenSquares : (int * int) list =
    [for i in 0 .. 5 do            //    [(0, 0), (2, 4), (4, 16)]
        if i % 2 = 0 then
            yield i, i*i]

let evenSquares' = 
  [ -1 .. 5 ]
  |> List.filter (fun i -> i%2 = 0)
  |> List.map (fun i -> i, i * i)

Equivalency

1: 
2: 
evenSquares = evenSquares'                  // val it : bool = true
obj.ReferenceEquals(1 :: x |> List.tail, x) // val it : bool = true

Sequences

1: 
let notThatMuch = Seq.empty
1: 
let range = seq { 1 .. 42 }
1: 
2: 
3: 
4: 
5: 
let (height, width) = (10, 10)
seq {
    for row in 0 .. width - 1 do
        for col in 0 .. height - 1 ->
            (row, col, row*width + col) }
1: 
2: 
3: 
let fib = Seq.unfold(fun (n1, n2) ->
    Some(n1 + n2, (n2, n1 + n2))) (0I, 1I)
fib |> Seq.item 100
927372692193078999176

Arrays

1: 
let arr = [| 41; 42 |]

Pattern Matching

Structure

    match test-expression with
    | pattern1 [ when condition ] -> result-expression1
    | pattern2 [ when condition ] -> result-expression2
    | ...
    function
    | pattern1 [ when condition ] -> result-expression1
    | pattern2 [ when condition ] -> result-expression2
    | ...

Exceptions

1: 
2: 
3: 
4: 
5: 
6: 
try
    "Something"
with
| :? ArgumentException as ex when ex.Message = "Hi" -> "Hello"
| :? InvalidOperationException -> "Can't do" 
| ex -> sprintf "%s, WTF?" ex.Message

Lists

1: 
2: 
3: 
4: 
5: 
match [1; 2; 3] with
| [] -> "Empty"
| [x] -> "List with only x"
| x :: y :: z :: _ -> "List with at least 3 elements"
| x :: xs -> "List with head x and tail xs"

Discriminated unions

1: 
2: 
3: 
4: 
5: 
match Some 2.718 with
| Some e when e > 0.0 -> "Probably e"
| Some 0.0 -> "Zero, for sure"
| Some _ -> "Who cares"
| _ -> "And the rest"

Records

1: 
2: 
3: 
4: 
5: 
6: 
let greet = function
| { FirstName = "W.A."; LastName = ln } ->
    sprintf "My name is W.A., W.A. %s" ln
| { DoD = Some _ } -> "👼"
| { DoB = d } when d > DateTime.UtcNow -> "Marty"
| { FirstName = fn } -> sprintf "Hello, %s" fn

Types

1: 
2: 
3: 
4: 
match box 12 with
| :? int -> typeof<int>.Name
| :? double as d -> string d
| _ -> "Rest"

Exhaustive

warning FS0025: Incomplete pattern matches on this expression. For example, the value '...' may indicate a case not covered by the pattern(s).
warning FS0026: This rule will never be matched
warning FS0067: This type test or downcast will always hold

Active patterns

Complete

let (|Identifer1|Identifier2|...|) arguments = expression
Partition
1: 
2: 
3: 
4: 
5: 
let (|Even|Odd|) x = if x % 2 = 0 then Even else Odd

match 7 with
| Even -> "||"
| Odd  -> "~~"
Decompose
1: 
2: 
3: 
4: 
5: 
let (|RGB|) (color : System.Drawing.Color) =
    (color.R, color.G, color.B)

let printRGB = function
    RGB(r, g, b) -> printf "(R:%i, G:%i, B:%i)" r g b

Partial

let (|Ident|_|) [ arguments ] = expression
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
let (|Integer|_|) input =
    match Int32.TryParse input with
    | true, d -> Some d
    | _ -> None

open System.Text.RegularExpressions
let (|Parse|_|) regex input =
    let m = Regex(regex).Match(input)
    if m.Success then
        List.tail [for g in m.Groups -> g.Value] |> Some
    else
        None
1: 
2: 
3: 
4: 
5: 
match "pwd123" with
| Integer i -> "Key space too small"
| Parse "^(\d{1,2})\.(\d{1,2})\.(\d{1,4})$" [Integer d; Integer m; Integer y] ->
    sprintf "%A... wife or girlfriend?" <| DateTime(y, m, d)
| s -> sprintf "Logging secure password %s" s

Computation Expressions

Monads, Monads, Monads, Monads, Monads
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
Bind : M<'T> * ('T -> M<'U>) -> M<'U>           // let!, do!
Delay : (unit -> M<'T>) -> M<'T>
Return : 'T -> M<'T>                            // return
ReturnFrom : M<'T> -> M<'T>                     // return!
Run : M<'T> -> 'T
Combine : M<'T> * M<'T> -> M<'T>
For : seq<'T> * ('T -> M<'U>) -> M<'U>          // for .. do
TryFinally : M<'T> * (unit -> unit) -> M<'T>    // try .. finally
TryWith : M<'T> * (exn -> M<'T>) -> M<'T>       // try .. with
Using : 'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable
While : (unit -> bool) * M<'T> -> M<'T>         // while .. do
Yield : 'T -> M<'T>                             // yield
YieldFrom : M<'T> -> M<'T>                      // yield!
Zero : unit -> M<'T>                            // if .. then .. (no else)

builder.Run(builder.Delay(fun () -> {| cexpr |}))

async

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
open System.Threading
let res =
    async {
        let u = Uri("https://caring.dev")
        let ctx = SynchronizationContext.Current
        do! Async.SwitchToThreadPool()
        use client = new System.Net.WebClient()
        let! b = client.AsyncDownloadData u
        let s = System.Text.Encoding.UTF8.GetString b
        do! Async.SwitchToContext ctx
        return s
    }
    |> Async.Catch
    |> Async.RunSynchronously

match res with
| Choice1Of2 r -> printfn "Got %s" r
| Choice2Of2 exn -> printfn "Failed with %s" exn.Message

Type Providers

An F# type provider is a component that provides types, properties, and methods for use in your program. [...] Writing these types manually is very time-consuming and difficult to maintain. A common alternative is to use a code generator which adds files to your project [...]
Visual F# docs

  • Worldbank
  • Xml, Json, CSV, Ini, Resx
  • DbmlFile, EdmxFile
  • SqlDataConnection, SqlEntityConnection
  • WsdlService, ODataService, Swagger
  • AppSettings
  • Excel, R, Matlab
  • Management
  • Azure
  • ...

Yaml

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
Meetup:
    topic: "F# intro"
    author: Raphael Schweizer
    contents:
        - Getting started
        - Bindings
        - Functions
        - Datatypes
        - ...
    duration: 2
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
#I "../../packages/FSharp.Configuration/lib/net45"
#r "FSharp.Configuration.dll"
open FSharp.Configuration

type Config = YamlConfig<"config.yml">

let config = (Config()).Meetup
printfn "The %s meetup takes %ih" config.topic config.duration

XML

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
<?xml version="1.0" encoding="UTF-8" ?>
<messages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <message>
        <Available>Foo</Available>
        <Nil xsi:nil="true"/>
        <Missing>Bar</Missing>
        <Missing_Nil>1337</Missing_Nil>
    </message>
    <message>
        <Available>Baz</Available>
        <Nil>3.141</Nil>
    </message>
    <message>
        <Available></Available>
        <Nil>2.718</Nil>
        <Missing_Nil xsi:nil="true"/>
    </message>
</messages>
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
#I "../../packages/FSharp.Data/lib/net40"
#r "FSharp.Data.dll"
open FSharp.Data

type Message = XmlProvider<"sampleMessages.xml", SampleIsList = true>

let xml = Message.Load("message.xml")

(xml.Available : string option)
let nil : Message.Nil = xml.Nil
(nil.Nil : bool option)
(nil.Value : decimal option)
(xml.Missing : string option)
let missingNil : Message.MissingNil option =
    xml.MissingNil
missingNil |> Option.map(fun mn ->
    (mn.Nil : bool option) |> ignore
    (mn.Value : int option))

Units of Measure

1: 
2: 
3: 
var timeout = 12;
Thread.Sleep(timeout);
// Correct? Order of magnitude too long / short?
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
[<Measure>] type s

[<Measure>]
type ms =
    static member perSecond = 1000.0<ms/s>

let timeout = 12.0<s>
timeout * ms.perSecond  // val it : float<ms> = 12000.0
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
open Microsoft.FSharp.Data.UnitSystems.SI.UnitSymbols

module Symbols =
    let distance = 1.0<m>
    let time = 2.0<s>
    let speed = distance/time
    let acceleration = speed/time
    let mass = 5.0<kg>
    let force : float<N> = mass * speed/time // kg * m / s^2
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames

module Names =
    let distance = 1.0<metre>
    let time = 2.0<second>
    let speed = distance/time
    let acceleration = speed/time
    let mass = 5.0<kilogram>
    let force : float<newton> = mass * speed/time // kg * m / s^2
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
type FxRate<[<Measure>] 'u, [<Measure>] 'v> =
    { Rate: float<'u/'v>; Date: DateTime }

[<Measure>] type CHF
[<Measure>] type GBP

let gbp : FxRate<GBP, CHF> list = [
    { Rate = 1.54<GBP/CHF>; Date = DateTime(2015, 11, 27) }
    { Rate = 1.27<GBP/CHF>; Date = DateTime(2016, 7, 8) } ]

Duck-typing

If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

Statically resolved type parameters

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
let inline op (a : ^T1) (b : ^T2) : ^T3 = a ? b

let inline div a b = a %% b
// val inline div :
//   a: ^a -> b: ^b ->  ^_arg3
//     when ( ^a or  ^b) : (static member ( %% ) :  ^a *  ^b ->  ^_arg3)

let inline (+@) x y = x + x % y
1 +@ 2
3.0 +@ 4.5
// val inline ( +@ ) :
//   x: ^a -> y: ^c ->  ^d
//     when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^d) and
//          ( ^a or  ^c) : (static member ( % ) :  ^a *  ^c ->  ^b)

Member constraints

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
let inline optionOfNillable n =
    match (^N : (member Nil : bool option) n) with
    | Some true -> None
    | _ -> (^N : (member Value : 'T option) n)

// val inline optionOfNillable :
//   n: ^N -> 'T option
//     when  ^N : (member get_Nil :  ^N -> bool option) and
//           ^N : (member get_Value :  ^N -> 'T)

let nil' =
    xml.Nil |> optionOfNillable
let missingNil' =
    xml.MissingNil |> Option.bind optionOfNillable

Modules

Classes

Interfaces

Signatures

Other great stuff

  • typesafe print family
  • |> ignore
  • MailboxProcessor
  • type Other with
  • <@ ... @> quotations
  • use
  • fsi signature files
  • very cool libraries

Psst...

  • Tooling (Refactoring)
  • Everything gets worse (initially)

C# → F# interoperability

1: 
2: 
3: 
4: 
5: 
6: 
7: 
open System.Runtime.InteropServices

[<CompiledName("FooC")>]
type ``Foo C#`` =
    static member Bar([<Optional; DefaultParameterValue(null)>] ?c) =
        let c = defaultArg c 1
        42 * c

F# types: option, list, FSharpFunc, ...

Questions?

Raphael Schweizer

@_Caring_Dev_

caring.dev



Creative Commons License