val getHtml : url:string -> 'a Full name: index.getHtml
val url : string
Multiple items val string : value:'T -> string Full name: Microsoft.FSharp.Core.Operators.string -------------------- type string = System.String Full name: Microsoft.FSharp.Core.string
val req : obj
val response : obj
val streatm : System.IDisposable
val reader : System.IDisposable
val getHtmlA : url:string -> Async<'a> Full name: index.getHtmlA
val async : AsyncBuilder Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val getHtmlA : url:string -> 'a Full name: index.getHtmlA
val req : 'a
val response : 'a
val streatm : 'a (requires 'a :> System.IDisposable)
val reader : 'a (requires 'a :> System.IDisposable)
union case Option.Some: Value: 'T -> Option<'T>
val printfn : format:Printf.TextWriterFormat<'T> -> 'T Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
namespace System
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<'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.Sleep : millisecondsDueTime:int -> Async<unit>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
val sprintf : format:Printf.StringFormat<'T> -> 'T Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val failwith : message:string -> 'T Full name: Microsoft.FSharp.Core.Operators.failwith
Multiple items val byte : value:'T -> byte (requires member op_Explicit) Full name: Microsoft.FSharp.Core.Operators.byte -------------------- type byte = System.Byte Full name: Microsoft.FSharp.Core.byte
Multiple items module List from Microsoft.FSharp.Collections -------------------- type List<'T> = | ( [] ) | ( :: ) of Head: 'T * Tail: 'T list interface IEnumerable interface IEnumerable<'T> 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 reduce : reduction:('T -> 'T -> 'T) -> list:'T list -> 'T Full name: Microsoft.FSharp.Collections.List.reduce
union case Option.None: Option<'T>
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<_>
module Seq from Microsoft.FSharp.Collections
val fold : folder:('State -> 'T -> 'State) -> state:'State -> source:seq<'T> -> 'State Full name: Microsoft.FSharp.Collections.Seq.fold
Computation expressions in context
FP User Group + Craft Conf - April 2016
Andrea Magnorsky
@SilverSpoon
introduce comp expressions
Computation Expressions
1:
2:
3:
4:
5:
6:
7:
let getHtml (url : string ) =
let req = WebRequest . Create url
let response = req . GetResponse ()
use streatm = response . GetResponseStream ()
use reader = new StreamReader (streatm )
reader . ReadToEnd (). Length
1:
2:
3:
4:
5:
6:
7:
8:
let getHtmlA (url : string ) =
async {
let req = WebRequest . Create url
let! response = req . AsyncGetResponse () // ding!
use streatm = response . GetResponseStream ()
use reader = new StreamReader (streatm )
return reader . ReadToEndAsync (). Length // ding!
}
1:
2:
3:
4:
5:
6:
7:
8:
let getHtmlA (url : string ) =
//async{
let req = WebRequest . Create url
let (*! *) response = req . AsyncGetResponse ()
use streatm = response . GetResponseStream ()
use reader = new StreamReader (streatm )
(*return *) reader . ReadToEndAsync (). Length
// }
1:
2:
3:
4:
5:
6:
7:
8:
let maybe = new MaybeBuilder ()
let addNUmbers =
maybe {
let x = 12
let! y = Some 11
let! z = Some 30
return x + y + z
}
Block of code that represent a computation with a non standard aspect
code inside the block is reinterpreted using a computation builder
record of operations that define the semantics and syntax
type SimplestBuilder () =
1:
2:
3:
4:
5:
6:
7:
8:
member this . Bind (x ,f ) =
printfn "Bind begin %A %s " (DateTime . Now . TimeOfDay ) (x . ToString ())
let y = f x
printfn "Bind end %A %s " (DateTime . Now . TimeOfDay ) (x . ToString ())
y
member this . Return (x ) =
printfn "Return %A %s" (DateTime . Now . TimeOfDay ) (x . ToString ())
x
async
1:
2:
3:
4:
5:
6:
7:
8:
9:
open System
let sleepWorkflow = async {
printfn "Starting at %O" DateTime . Now . TimeOfDay
do! Async . Sleep 2000
printfn "Finished at %O" DateTime . Now . TimeOfDay
}
Async . RunSynchronously sleepWorkflow
mbrace
1:
2:
3:
4:
5:
let job =
cloud {
return sprintf
"run on worker '%s' " Environment . MachineName }
|> runtime . CreateProcess
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
let makeJob i =
cloud {
if i % 8 = 0 then failwith "fail"
let primes = Sieve . getPrimes 1000000
return sprintf
"calculated %d primes %A on machine '%s'"
primes . Length
primes
Environment . MachineName
}
let jobs2 =
[ for i in 1 .. 10 ->
makeJob i |> cluster . CreateProcess ]
example source
read -> maths heavy
first person to describe monads for functional programming was Eugenio Moggi, paper called ["Notions of computation and monads"](http://www.disi.unige.'it/person/MoggiE/ftp/ic91.pdf) this paper is maths heavy tho I am sure some of you will be interested in looking at this.
Notions of computation and monads (1991)
Philip Wadler, these papers made monads in programming widely known.
Comprehending Monads (1990)
Monads for functional programming (1995)
purity vs impurity and how when trying to keep pure certain things become harder than they would be in imperative code
F# is an impure language
Pure language: it has referential transparency, so, you can replace any expression with its value without changing the meaning of the program.
Some not-useful-right-away info
There is a strong link between monads and category theory
Monads have 3 monadic laws that every monad must satisfy:
Left identity
Right identity and
Associativity
Monads eh?
lots of noise many monads tutorials
f# not a pure language
Monoids
Convert pairwise operations into work in collections
Parallelization and Incrementalism
Monoids
Closures \(a' \rightarrow a' \rightarrow a'\) (example int -> int -> int )
Identity \(x + I = x\)
Associativity \(x + (y + z) = (x + y ) + z\)
1:
2:
3:
4:
5:
6:
7:
8:
type Colour = { r : byte ; g : byte ; b : byte ; a : byte }
let addTwo c1 c2 = {
r = c1 . r + c2 . r
g = c1 . g + c2 . g
b = c1 . b + c2 . b
a = c1 . a + c2 . a
}
1:
2:
3:
type Monoid < ' a > =
{ neutral : ' a
op : ' a -> ' a -> ' a }
1:
2:
3:
4:
5:
6:
let black = { r = 0uy ; g = 0uy ; b = 0uy ; a = 0uy }
let colourAdd : Monoid < Colour > = {
neutral = black
op = (addTwo )
}
1:
2:
3:
4:
5:
let c1 = { black with g = 254uy }
let c2 = { black with r = 254uy }
let l = [ c1 ; c2 ; black ]
|> List . reduce (addTwo )
Oh, yes and you can property check that your type is a monoid!!
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
type T = Colour
let M = colourAdd
let Z = M . neutral
let (++ ) = M . op
[<Property >]
let `` Z is the neutral element`` (v : T ) =
Z ++ v = v && v ++ Z = v
[<Property >]
let ``The op is associative`` (a : T , b : T , c : T ) =
a ++ (b ++ c ) = (a ++ b ++ c )
Because of closures-> We can convert pairwise operations into operations that work on collections
Because of associativity -> We can implement divide and conquer algorithms that are great for
Parallelization
Incrementalism
Because of identity -> we can actually perform certain of the above
A monad is a monoid in the category of endofunctors.
A monad is like a burrito.
Think of monads just like you would think about Legos.
It all seemed pretty strange to me and I wound up understanding less and less
then I see this in the news!! Is there some sort of link between otters and monads?
Wadler talked about handling errors in his monad paper, MAYBE we should try to write some code and see how can we use this stuff
Errors
1:
2:
3:
4:
5:
6:
7:
8:
let division a b c d =
match b with
| 0 -> None
| _ -> match c with
| 0 -> None
| _ -> match d with
| 0 -> None
| _ -> Some (((a / b )/ c )/ d )
1. Extract the core
1:
2:
3:
4:
let divide a b =
match b with
| 0 -> None
| _ -> Some (a / b )
2. Write the Builder
1:
2:
3:
4:
5:
6:
type MaybeBuilder () =
member __ . Bind (value , func ) =
match value with
| Some value -> func value
| None -> None
member __ . Return value = Some value
3. Profit
1:
2:
3:
4:
5:
6:
7:
8:
9:
let maybe = MaybeBuilder ()
let divisionM a b c d =
maybe {
let! x = divide a b
let! y = divide x c
let! z = divide y d
return z
}
what is happening here ?
Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function >>= (pronounced “bind”) to do this.
oh, oh! and you can also property check a monad (tho a little harder to read than the monoids)
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
[<Test >]
let ``monad laws`` () =
let ret (x : int ) = choose . Return x
let n = sprintf "Choice : monad %s"
let inline (> > = ) m f = choose . Bind (m ,f )
fsCheck "left identity" <|
fun f a -> ret a > > = f = f a
fsCheck "right identity" <|
fun x -> x > > = ret = x
fsCheck "associativity" <|
fun f g v ->
let a = (v > > = f ) > > = g
let b = v > > = (fun x -> f x > > = g )
a = b
Why learn this?
how many of you read about DDD's ubiquitous language?
Because understanding the abstraction and having a common language is worth it
enables pure FP to represent non functions such as IO, state
control side effect (via the type system)
metaprogramming (haskell, c++ via templates)
Computation Expressions
Most monads are computation expressions, not all computation expressions are monads
let, for and try .. with, but with a different semantics
Monoids again
1:
2:
3:
4:
5:
6:
7:
8:
9:
type Colour = { r : byte ; g : byte ; b : byte ; a : byte }
let addColour c1 c2 =
{ r = c1 . r + c2 . r
g = c1 . g + c2 . g
b = c1 . b + c2 . b
a = c1 . a + c2 . a }
let neutral = { r = 0uy ; g = 0uy ; b = 0uy ; a = 0uy }
1:
2:
3:
4:
5:
6:
7:
8:
type MonoidBuilder ()=
member this . Zero () = neutral
member this . Combine (x , y ) = addColour x y
member x . For (sequence , f ) =
let combine a b = x . Combine (a , f b )
let Z = x . Zero ()
Seq . fold combine Z sequence
member x . Yield (a ) = a
1:
2:
3:
4:
5:
6:
let monoid = new MonoidBuilder ()
let monoidAdd xs = monoid {
for x in xs do
yield x
}
Computation expressions or workflows
Computation expressions have been available in F# since 2007 and they are fully documented in the F# language specification
Abstract computations
Handling of effects
Maybe problems
Slow
Hard to debug
Operator overuse
Next