namespace System
type Result<'success,'failure> =
  | Success of 'success
  | Failure of 'failure

Full name: Funwithfsharp.Result<_,_>
union case Result.Success: 'success -> Result<'success,'failure>
Multiple items
union case Result.Failure: 'failure -> Result<'success,'failure>

--------------------
active recognizer Failure: exn -> string option

Full name: Microsoft.FSharp.Core.Operators.( |Failure|_| )
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Data
type DirectoryPath = string

Full name: Funwithfsharp.DirectoryPath
Multiple items
val string : value:'T -> string

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

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

Full name: Microsoft.FSharp.Core.string
type FilePath = string

Full name: Funwithfsharp.FilePath
type TimeTaken = DateTimeOffset

Full name: Funwithfsharp.TimeTaken
Multiple items
type DateTimeOffset =
  struct
    new : dateTime:DateTime -> DateTimeOffset + 5 overloads
    member Add : timeSpan:TimeSpan -> DateTimeOffset
    member AddDays : days:float -> DateTimeOffset
    member AddHours : hours:float -> DateTimeOffset
    member AddMilliseconds : milliseconds:float -> DateTimeOffset
    member AddMinutes : minutes:float -> DateTimeOffset
    member AddMonths : months:int -> DateTimeOffset
    member AddSeconds : seconds:float -> DateTimeOffset
    member AddTicks : ticks:int64 -> DateTimeOffset
    member AddYears : years:int -> DateTimeOffset
    ...
  end

Full name: System.DateTimeOffset

--------------------
DateTimeOffset()
DateTimeOffset(dateTime: DateTime) : unit
DateTimeOffset(ticks: int64, offset: TimeSpan) : unit
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : unit
type MoveRequest =
  {Source: FilePath;
   Destination: FilePath;}

Full name: Funwithfsharp.MoveRequest
MoveRequest.Source: FilePath
MoveRequest.Destination: FilePath
type FailedMove =
  {Request: MoveRequest;
   Message: string;}

Full name: Funwithfsharp.FailedMove
FailedMove.Request: MoveRequest
FailedMove.Message: string
type File =
  {FullPath: FilePath;
   Name: string;}

Full name: Funwithfsharp.File
File.FullPath: FilePath
File.Name: string
type Picture =
  {File: File;
   TakenOn: TimeTaken;}
  member formatTakenOn : string

Full name: Funwithfsharp.Picture
Multiple items
Picture.File: File

--------------------
type File =
  {FullPath: FilePath;
   Name: string;}

Full name: Funwithfsharp.File
Picture.TakenOn: TimeTaken
val this : Picture
member Picture.formatTakenOn : string

Full name: Funwithfsharp.Picture.formatTakenOn
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
property DateTimeOffset.Year: int
property DateTimeOffset.Month: int
Multiple items
union case Result.Failure: 'failure -> Result<'success,'failure>

--------------------
type Failure =
  | BytesDidNotMatch of MoveRequest
  | CouldNotCopyFile of FailedMove
  | CouldNotDeleteSource of FailedMove
  | OhDearGodItAllBlewUp

Full name: Funwithfsharp.Failure
union case Failure.BytesDidNotMatch: MoveRequest -> Failure
union case Failure.CouldNotCopyFile: FailedMove -> Failure
union case Failure.CouldNotDeleteSource: FailedMove -> Failure
union case Failure.OhDearGodItAllBlewUp: Failure
val formatFailure : failure:Failure -> string

Full name: Funwithfsharp.formatFailure
val failure : Failure
val request : MoveRequest
val move : FailedMove
val report : numberOfSuccesses:int -> author:string -> string

Full name: Funwithfsharp.report
val numberOfSuccesses : int
val author : string
val reported : string

Full name: Funwithfsharp.reported
val mapSomeOrNone : f:('a -> 'b) -> things:'a list -> seq<'b> option

Full name: Funwithfsharp.mapSomeOrNone
val f : ('a -> 'b)
val things : 'a list
val x : 'a
val xs : 'a list
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val mapped : seq<int> option

Full name: Funwithfsharp.mapped
val x : int
val notMapped : seq<int> option

Full name: Funwithfsharp.notMapped
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 choose : chooser:('T -> 'U option) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.choose
type Tags = obj

Full name: Funwithfsharp.Tags
val tags : seq<obj>

Full name: Funwithfsharp.tags
val picture : obj

Full name: Funwithfsharp.picture
val find : predicate:('T -> bool) -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.find
val pic : obj
val aperture : obj

Full name: Funwithfsharp.aperture
namespace System.Diagnostics
val processStartInfo : ProcessStartInfo

Full name: Funwithfsharp.processStartInfo
Multiple items
type ProcessStartInfo =
  new : unit -> ProcessStartInfo + 2 overloads
  member Arguments : string with get, set
  member CreateNoWindow : bool with get, set
  member Domain : string with get, set
  member EnvironmentVariables : StringDictionary
  member ErrorDialog : bool with get, set
  member ErrorDialogParentHandle : nativeint with get, set
  member FileName : string with get, set
  member LoadUserProfile : bool with get, set
  member Password : SecureString with get, set
  ...

Full name: System.Diagnostics.ProcessStartInfo

--------------------
ProcessStartInfo() : unit
ProcessStartInfo(fileName: string) : unit
ProcessStartInfo(fileName: string, arguments: string) : unit
property ProcessStartInfo.FileName: string
property ProcessStartInfo.Arguments: string
Multiple items
type Process =
  inherit Component
  new : unit -> Process
  member BasePriority : int
  member BeginErrorReadLine : unit -> unit
  member BeginOutputReadLine : unit -> unit
  member CancelErrorRead : unit -> unit
  member CancelOutputRead : unit -> unit
  member Close : unit -> unit
  member CloseMainWindow : unit -> bool
  member EnableRaisingEvents : bool with get, set
  member ExitCode : int
  ...

Full name: System.Diagnostics.Process

--------------------
Process() : unit
Process.Start(startInfo: ProcessStartInfo) : Process
Process.Start(fileName: string) : Process
Process.Start(fileName: string, arguments: string) : Process
Process.Start(fileName: string, userName: string, password: Security.SecureString, domain: string) : Process
Process.Start(fileName: string, arguments: string, userName: string, password: Security.SecureString, domain: string) : Process
val runAsync : move:('a -> 'b) -> ('a list -> 'b list)

Full name: Funwithfsharp.runAsync
val move : ('a -> 'b)
val asyncMove : ('a -> Async<'b>)
val request : 'a
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
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.Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:Threading.CancellationToken -> 'T
val ofArray : array:'T [] -> 'T list

Full name: Microsoft.FSharp.Collections.List.ofArray
val compareFiles : compare:(string -> string -> bool) -> x:string -> y:string -> string

Full name: Funwithfsharp.compareFiles
val compare : (string -> string -> bool)
val x : string
val y : string
val badStrategy : x:'a -> y:'a -> bool (requires equality)

Full name: Funwithfsharp.badStrategy
val x : 'a (requires equality)
val y : 'a (requires equality)
val areEqual : string

Full name: Funwithfsharp.areEqual
val ( Verify Awww... when things don't match up ) : unit -> 'a

Full name: Funwithfsharp.( Verify Awww... when things don't match up )
val stubComparer : ('b -> 'c -> bool)
val x : 'b
val y : 'c
val comparison : string
val isOlderThanXMonths : currentTime:DateTimeOffset -> months:int -> date:DateTimeOffset -> bool

Full name: Funwithfsharp.isOlderThanXMonths
val currentTime : DateTimeOffset
val months : int
val date : DateTimeOffset
DateTimeOffset.AddMonths(months: int) : DateTimeOffset
val now : DateTimeOffset

Full name: Funwithfsharp.now
property DateTimeOffset.UtcNow: DateTimeOffset
val isOlderThan1Month : (DateTimeOffset -> bool)

Full name: Funwithfsharp.isOlderThan1Month
val firstOldDate : DateTimeOffset

Full name: Funwithfsharp.firstOldDate
val i : float
DateTimeOffset.AddDays(days: float) : DateTimeOffset

Some cool stuff I liked in F# while building a pet project in my spare time

Koen Metsu

What's my pet project about?

  • Image archiver
  • Uses ExifTool (perl) to extract EXIF|XMP|... data
  • Archives based on date taken

Muffin.Pictures.Archiver on GitHub

What's F# about?

  • Functional-first language
  • Open source
  • Cross-platform

What's F# about?

  • .NET Interoperability
  • Immutable by default
  • Strong type-system
  • Concise yet robust
  • Awesome community

Now for the cool stuff

(that I actually used in my application)

Easy to create wrapper types

Let's say you want a wrapper around a string in C#

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
public class DirectoryPath
{
    private readonly string _path;

    public DirectoryPath(string path)
    {
        _path = path;
    }

    public string Path
    {
        get { return _path; }
    }

    public static implicit operator string(DirectoryPath directoryPath)
    {
        return directoryPath.Path;
    }
}

Easy to create wrapper types

Let's say you want a wrapper around a string in F#

1: 
2: 
3: 
4: 
5: 
type DirectoryPath = string

type FilePath = string

type TimeTaken = DateTimeOffset

Easy to create data types

(your plain old POCO)

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
type MoveRequest = { Source : FilePath;
                     Destination : FilePath }

type FailedMove = { Request : MoveRequest;
                    Message : string }

type File = { FullPath:FilePath;
              Name:string }

Easy to extend types

1: 
2: 
3: 
4: 
5: 
6: 
type Picture = { File:File;
                 TakenOn:TimeTaken } with
        member this.formatTakenOn =
            sprintf "%i-%02i"
                this.TakenOn.Year
                this.TakenOn.Month

Easy to create union types

(kind of like enums but way cooler)

1: 
2: 
3: 
4: 
5: 
type Failure =
    | BytesDidNotMatch of MoveRequest
    | CouldNotCopyFile of FailedMove
    | CouldNotDeleteSource of FailedMove
    | OhDearGodItAllBlewUp

Type safety: pattern matching

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let formatFailure failure =
        match failure with
        | BytesDidNotMatch request ->
            "Reason: Bytes did not match"
        | CouldNotCopyFile move ->
            sprintf "Reason: Could not copy %A" move
        | CouldNotDeleteSource move ->
            "Reason: Could not delete source"
        | OhDearGodItAllBlewUp ->
            "You handle it from here"

Type safety: string formatting

1: 
2: 
3: 
4: 
5: 
6: 
let report numberOfSuccesses author =
    sprintf "%i successes, go %s!"
        numberOfSuccesses
        author

let reported = report 1000000 "Koen"
"1000000 successes, go Koen!"

Type safety: inference

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let mapSomeOrNone f things =
    match things with
    | x::xs -> things |> Seq.map f |> Some
    | _ -> None

let mapped = mapSomeOrNone (fun x -> x + 20) [0 ; 5 ; 10]
let notMapped = mapSomeOrNone (fun x -> x + 20) []
Some (seq [20; 25; 30])
<null>

Easily pipeline operations

1: 
2: 
3: 
4: 
5: 
6: 
7: 
moveRequests
|> List.choose isSuccess
|> moveInParallel move
|> tee (fun _ -> watch.Stop())
|> createReport moveRequests
|> tee reportToConsole
|> reportToMailIfNecessary arguments

Compose operations with ROP

1: 
2: 
3: 
4: 
let move moveWithFs compareFiles cleanUp =
    moveWithFs
    >=> compareFiles
    >=> cleanUp

Railway-Oriented-Programming

source

F# Type providers

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
open FSharp.Data

type Tags = JsonProvider<"example.json">
let tags = Tags.Load ("someFile.json")

let picture =
    tags
    |> Seq.find (fun pic -> pic.FileName = "bla")

let aperture = picture.Aperture

example json

.NET Interoperability

1: 
2: 
3: 
4: 
5: 
6: 
7: 
open System.Diagnostics
let processStartInfo = new ProcessStartInfo()
processStartInfo.FileName <- "killdestroy.exe"
processStartInfo.Arguments <-
    sprintf "/r /y /c /b /a /r %i" 1234

Process.Start(processStartInfo)

Easy async

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let runAsync move =
    let asyncMove request =
        async { return move request }

    List.map asyncMove
    >> Async.Parallel
    >> Async.RunSynchronously
    >> List.ofArray

Functions as interfaces

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let compareFiles compare x y =
    if compare x y then
        sprintf
            "Wow! %s IS %s!" x y
    else
        "Awww..."

let badStrategy x y = x <> y
let areEqual = compareFiles badStrategy "Time" "Money"
"Wow! Time IS Money!"

Easy stubs!

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
open Swensen.Unquote

let ``Verify Awww... when things don't match up`` () =
    let stubComparer x y = false
    let comparison =
        compareFiles stubComparer "Time" "Money"

    test <@ "Awww..." = comparison @>

Partial application

1: 
2: 
3: 
4: 
5: 
6: 
let now = DateTimeOffset.UtcNow
let isOlderThan1Month = isOlderThanXMonths now 1
let firstOldDate =
    [ 0.0 .. 8.0 .. 100.0 ]
    |> Seq.map (fun i -> now.AddDays(-i))
    |> Seq.find isOlderThan1Month
No value has been returned

More information

F# official site

F# For Fun and Profit

FSharp

@koenmetsu