val isBob : name:string -> string
Full name: Index.isBob
val name : string
val isName1 : matchName:string -> personName:'a -> string
Full name: Index.isName1
val matchName : string
val personName : 'a
val sprintf : format:Printf.StringFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val isName2 : matchName:string -> personName:'a -> string (requires equality)
Full name: Index.isName2
val personName : 'a (requires equality)
val str : 'a (requires equality)
val expected : 'a (requires equality)
val value : 'a (requires equality)
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val niceIsName : matchName:string -> personName:string -> string
Full name: Index.niceIsName
val personName : string
active recognizer Eq: 'a -> 'a -> unit option
Full name: Index.( |Eq|_| )
namespace System
val dbForwarder : str:'a -> unit
Full name: Index.dbForwarder
val str : 'a
val consoleForwarder : str:'a -> unit
Full name: Index.consoleForwarder
Multiple items
module Map
from Microsoft.FSharp.Collections
--------------------
type Map<'Key,'Value (requires comparison)> =
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
override Equals : obj -> bool
member Remove : key:'Key -> Map<'Key,'Value>
...
Full name: Microsoft.FSharp.Collections.Map<_,_>
--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.tryFind
val makeForwarder : _arg1:Map<string,string> -> unit
Full name: Index.makeForwarder
active recognizer Val: 'a -> Map<'a,'b> -> 'b option
Full name: Index.( |Val|_| )
val conn : string
val prefix : string
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val s : string
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
Full name: System.Int64
Int64.TryParse(s: string, result: byref<int64>) : bool
Int64.TryParse(s: string, style: Globalization.NumberStyles, provider: IFormatProvider, result: byref<int64>) : bool
val v : int64
active recognizer AsInt64: string -> int64 option
Full name: Index.( |AsInt64|_| )
val x : int64
val tryGetPort : hostName:'a -> config:Map<'a,string> -> int64 option (requires comparison)
Full name: Index.tryGetPort
val hostName : 'a (requires comparison)
val config : Map<'a,string> (requires comparison)
val portNum : int64
Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Quotations
module ExprShape
from Microsoft.FSharp.Quotations
val expr : Expr
Full name: Index.expr
val traverse : expr:Expr -> Expr
Full name: Index.traverse
val expr : Expr
active recognizer ShapeVar: Expr -> Choice<Var,(Var * Expr),(obj * Expr list)>
Full name: Microsoft.FSharp.Quotations.ExprShape.( |ShapeVar|ShapeLambda|ShapeCombination| )
val v : Var
Multiple items
type Expr =
override Equals : obj:obj -> bool
member GetFreeVars : unit -> seq<Var>
member Substitute : substitution:(Var -> Expr option) -> Expr
member ToString : full:bool -> string
member CustomAttributes : Expr list
member Type : Type
static member AddressOf : target:Expr -> Expr
static member AddressSet : target:Expr * value:Expr -> Expr
static member Application : functionExpr:Expr * argument:Expr -> Expr
static member Applications : functionExpr:Expr * arguments:Expr list list -> Expr
...
Full name: Microsoft.FSharp.Quotations.Expr
--------------------
type Expr<'T> =
inherit Expr
member Raw : Expr
Full name: Microsoft.FSharp.Quotations.Expr<_>
static member Expr.Var : variable:Var -> Expr
active recognizer ShapeLambda: Expr -> Choice<Var,(Var * Expr),(obj * Expr list)>
Full name: Microsoft.FSharp.Quotations.ExprShape.( |ShapeVar|ShapeLambda|ShapeCombination| )
val body : Expr
static member Expr.Lambda : parameter:Var * body:Expr -> Expr
active recognizer ShapeCombination: Expr -> Choice<Var,(Var * Expr),(obj * Expr list)>
Full name: Microsoft.FSharp.Quotations.ExprShape.( |ShapeVar|ShapeLambda|ShapeCombination| )
val a : obj
val args : Expr list
val traversed : Expr list
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 map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
val RebuildShapeCombination : shape:obj * arguments:Expr list -> Expr
Full name: Microsoft.FSharp.Quotations.ExprShape.RebuildShapeCombination
val result : string
Full name: Index.result
namespace Swensen
namespace Swensen.Unquote
module Assertions
from Swensen.Unquote
val test1 : unit -> unit
Full name: Index.test1
val test : expr:Expr<bool> -> unit
Full name: Swensen.Unquote.Assertions.test
val test2 : unit -> unit
Full name: Index.test2
namespace FSharpComposableQuery
type Person =
{name: string;
age: int;}
Full name: Index.Person
Person.name: string
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
Person.age: int
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 people : Person list
Full name: Index.people
val aQuery : Person
Full name: Index.aQuery
val query : QueryImpl.QueryBuilder
Full name: FSharpComposableQuery.TopLevelValues.query
val p : Person
custom operation: sortBy ('Key)
Calls Linq.QueryBuilder.SortBy
custom operation: last
Calls Linq.QueryBuilder.Last
val filter : Expr<(Person -> bool)>
Full name: Index.filter
val q2 : filter:Expr<(Person -> bool)> -> seq<Person>
Full name: Index.q2
val filter : Expr<(Person -> bool)>
val filtered : seq<Person>
Full name: Index.filtered
Multiple items
type OptionBuilder =
new : unit -> OptionBuilder
member Bind : m:'b option * f:('b -> 'c option) -> 'c option
member Return : value:'a -> 'a option
Full name: Index.OptionBuilder
--------------------
new : unit -> OptionBuilder
val x : OptionBuilder
member OptionBuilder.Bind : m:'b option * f:('b -> 'c option) -> 'c option
Full name: Index.OptionBuilder.Bind
val m : 'b option
val f : ('b -> 'c option)
val value : 'b
member OptionBuilder.Return : value:'a -> 'a option
Full name: Index.OptionBuilder.Return
val value : 'a
Multiple items
val option : OptionBuilder
Full name: Index.option
--------------------
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
val maybeAdd : maybeA:int option -> maybeB:int option -> int option
Full name: Index.maybeAdd
val maybeA : int option
val maybeB : int option
val a : int
val b : int
namespace Hopac
val workToDo : Job<int>
Full name: Index.workToDo
val job : JobBuilder
Full name: Hopac.TopLevel.job
val async : AsyncBuilder
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val workDone : int
Full name: Index.workDone
type Job<'T> =
Full name: Hopac.Job<_>
module Global
from Hopac.Job
val run : Job<'x> -> 'x
Full name: Hopac.Job.Global.run
type AsyncBuilder =
private new : unit -> AsyncBuilder
member Bind : computation:Async<'T> * binder:('T -> Async<'U>) -> Async<'U>
member Combine : computation1:Async<unit> * computation2:Async<'T> -> Async<'T>
member Delay : generator:(unit -> Async<'T>) -> Async<'T>
member For : sequence:seq<'T> * body:('T -> Async<unit>) -> Async<unit>
member Return : value:'T -> Async<'T>
member ReturnFrom : computation:Async<'T> -> Async<'T>
member TryFinally : computation:Async<'T> * compensation:(unit -> unit) -> Async<'T>
member TryWith : computation:Async<'T> * catchHandler:(exn -> Async<'T>) -> Async<'T>
member Using : resource:'T * binder:('T -> Async<'U>) -> Async<'U> (requires 'T :> IDisposable)
...
Full name: Microsoft.FSharp.Control.AsyncBuilder
val x : AsyncBuilder
member AsyncBuilder.Bind : aJob:Job<'a> * f:('a -> Async<'b>) -> Async<'b>
Full name: Index.Bind
val aJob : Job<'a>
val f : ('a -> Async<'b>)
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<_>
val jobResult : 'a
module Extensions
from Hopac
module Async
from Hopac.Extensions
module Global
from Hopac.Extensions.Async
val ofJob : Job<'x> -> Async<'x>
Full name: Hopac.Extensions.Async.Global.ofJob
val asyncWorkToDo : Async<int>
Full name: Index.asyncWorkToDo
val asyncWorkDone : int
Full name: Index.asyncWorkDone
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:Threading.CancellationToken -> 'T
namespace FSharp.Text
namespace FSharp.Text.RegexProvider
type MyRegex = Regex<...>
Full name: Index.MyRegex
type Regex =
inherit Regex
member MatchTimeout : TimeSpan
member Options : RegexOptions
member RightToLeft : bool
val capnames : Hashtable
val caps : Hashtable
val capsize : int
val capslist : string []
val code : RegexCode
val factory : RegexRunnerFactory
...
Full name: FSharp.Text.RegexProvider.Regex
val regexed : Regex<...>.MatchType2
Full name: Index.regexed
val bobMcBob : Person
Full name: Index.bobMcBob
property Regex<...>.MatchType2.name: Text.RegularExpressions.Group
Gets the "name" group from this match
property Text.RegularExpressions.Capture.Value: string
property Regex<...>.MatchType2.age: Text.RegularExpressions.Group
Gets the "age" group from this match
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.Parse(s: string) : int
Int32.Parse(s: string, provider: IFormatProvider) : int
Int32.Parse(s: string, style: Globalization.NumberStyles) : int
Int32.Parse(s: string, style: Globalization.NumberStyles, provider: IFormatProvider) : int
val str : string
Regex<...>.IsMatch(input: string) : bool
Indicates whether the regular expression finds a match in the specified input string
Text.RegularExpressions.Regex.IsMatch(input: string, pattern: string) : bool
Text.RegularExpressions.Regex.IsMatch(input: string, pattern: string, options: Text.RegularExpressions.RegexOptions) : bool
Text.RegularExpressions.Regex.IsMatch(input: string, pattern: string, options: Text.RegularExpressions.RegexOptions, matchTimeout: TimeSpan) : bool
Int32.TryParse(s: string, result: byref<int>) : bool
Int32.TryParse(s: string, style: Globalization.NumberStyles, provider: IFormatProvider, result: byref<int>) : bool
val i : int
active recognizer IsMatch: string -> Choice<Regex<...>.MatchType2,unit>
Full name: Index.( |IsMatch|NotMatch| )
val regexed : Regex<...>.MatchType2
active recognizer AsInt: string -> int option
Full name: Index.( |AsInt|_| )
active recognizer NotMatch: string -> Choice<Regex<...>.MatchType2,unit>
Full name: Index.( |IsMatch|NotMatch| )
Solving Real World Problems...
...from the Ivory Tower
Handy helpers
Liberally stolen from this gist.
Thanks Karl Nilsson!
1:
2:
3:
4:
|
let isBob name =
match name with
| "bob" -> "It's bob!"
| _ -> "It's not bob!"
|
What about writing an isName
function?
1:
2:
3:
4:
5:
6:
7:
|
let isName1 matchName personName =
match personName with
| personName ->
sprintf "It's %s!" matchName
| _ ->
// This rule will never be matched...
sprintf "It's not %s!" matchName
|
1:
2:
3:
4:
5:
6:
|
let isName2 matchName personName =
match personName with
| str when str = personName ->
sprintf "It's %s!" matchName
| _ ->
sprintf "It's not %s!" matchName
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
|
let (|Eq|_|) expected value =
if expected = value then Some ()
else None
let niceIsName matchName personName =
match personName with
| Eq matchName ->
sprintf "It's %s!" matchName
| _ ->
sprintf "It's not %s!" matchName
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
|
let (|Val|_|) = Map.tryFind
let makeForwarder =
function
| Val "type" "db" & Val "connection" conn ->
dbForwarder conn
| Val "type" "console" & Val "prefix" prefix ->
consoleForwarder prefix
| _ -> failwith "wat?"
let (|AsInt64|_|) s =
match Int64.TryParse s with
| true, v -> Some v
| _ -> None
match "1234" with
| AsInt64 x -> "ok"
| _ -> "not ok"
|
Put 'em together
1:
2:
3:
4:
|
let tryGetPort hostName config =
match config with
| Val hostName (AsInt64 portNum) -> Some portNum
| _ -> None
|
Partitioning existing data
F# Quotations represent the AST of a piece of F# code; nodes in the tree
can be one of 38 cases
Let's say we want to transform if
statements and carry everything else through unchanged
That's 38 lines of code, or...
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
|
open FSharp.Quotations
open FSharp.Quotations.ExprShape
let expr = <@@ if 10 < 5 then "really?!" else "good" @@>
let rec traverse expr =
match expr with
| ShapeVar (v) ->
Expr.Var(v)
| ShapeLambda(v, body) ->
Expr.Lambda(v, traverse body)
| ShapeCombination(a, args) ->
let traversed = args |> List.map traverse
ExprShape.RebuildShapeCombination(a, traversed)
let result =
if expr = traverse expr then "Hurrah!" else "Boo!"
|
result:
Not just failing, but failing with style
1:
2:
3:
4:
5:
6:
|
open Swensen.Unquote.Assertions
let test1() =
test <@ 1 = 2 @>
test1()
|
1:
2:
3:
4:
5:
6:
7:
8:
|
let test2() =
test <@
[3;2;1;0]
|> List.map ((+) 1)
|> (=) [1 + 3..1 + 0]
@>
test2()
|
Test failed:
[3; 2; 1; 0] |> List.map ((+) 1) |> (=) [1 + 3..1 + 0]
[4; 3; 2; 1] |> (=) [4..1]
[4; 3; 2; 1] |> (=) []
false
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
|
open FSharpComposableQuery
type Person = { name: string; age: int }
let people = [
{ name = "bob"; age = 25 }
{ name = "fred"; age = 27 }
]
let aQuery =
query {
for p in people do
sortBy p.age
last
}
|
{name = "fred";
age = 27;}
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
|
let filter = <@ fun (p : Person) -> p.age < 27 @>
let q2 filter =
query {
for p in people do
if (%filter) p then yield p
}
let filtered = q2 filter
|
seq [{name = "bob";
age = 25;}]
|
Computational Expressions
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
|
type OptionBuilder () =
member x.Bind(m, f) =
match m with
| Some value -> f value
| None -> None
member x.Return value =
Some value
let option = OptionBuilder()
let maybeAdd maybeA maybeB =
option {
let! a = maybeA
let! b = maybeB
return a + b
}
// None
maybeAdd (Some 10) None
// Some 20
maybeAdd (Some 10) (Some 10)
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
|
open Hopac
let workToDo = job {
let! a = job { return 10 }
let! b = async { return 10 }
return a + b
}
let workDone = Job.Global.run workToDo
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
|
type AsyncBuilder with
member x.Bind(aJob : Job<'a>, f : 'a -> Async<'b>) =
job {
let! jobResult = aJob
return! f jobResult
} |> Extensions.Async.Global.ofJob
let asyncWorkToDo = async {
let! a = job { return 10 }
let! b = async { return 10 }
return a + b
}
let asyncWorkDone = asyncWorkToDo |> Async.RunSynchronously
|
Regex with one less problem
Also: text and video type provider tutorials on my blog
1:
2:
3:
4:
5:
6:
7:
8:
9:
|
open FSharp.Text.RegexProvider
type MyRegex = Regex<"""(?<name>.+):\s+(?<age>\d+)""">
let regexed = MyRegex().Match("Bob McBob: 42")
let bobMcBob =
{ name = regexed.name.Value
age = regexed.age.Value |> Int32.Parse }
|
{name = "Bob McBob";
age = 42;}
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
|
let (|IsMatch|NotMatch|) str =
match MyRegex.IsMatch str with
| true -> IsMatch (MyRegex().Match(str))
| false -> NotMatch
let (|AsInt|_|) str =
match Int32.TryParse str with
| true, i -> Some i
| false, _ -> None
let (|StringToPerson|_|) str =
match str with
| IsMatch regexed ->
match regexed.age.Value with
| AsInt i -> { name = regexed.name.Value
age = i } |> Some
| _ -> None
| NotMatch -> None
|