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 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) []
|
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
|
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"
|
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
|