Last active
August 29, 2015 14:17
-
-
Save johnazariah/63a88b2e13c06799a871 to your computer and use it in GitHub Desktop.
Attempt computation expression
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
[<AutoOpen>] | |
module Attempt = | |
type Result<'TSuccess> = | |
| Success of 'TSuccess | |
| Failure of Exception | |
// make sure f is pure, otherwise monad laws will fail | |
let (>>=) x f = | |
match x with | |
| Success s -> f s | |
| Failure ex -> Failure ex | |
let pureReturn x = Success x | |
let safe f = fun x -> try Success (f x) with ex -> Failure ex | |
type AttemptBuilder() = | |
member this.Bind (x, f) = x >>= f | |
member this.Return (x) = pureReturn x | |
let attempt = new AttemptBuilder () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let step01 () : Result<int> = Success (1) | |
let step02 () : Result<int> = Failure (new IndexOutOfRangeException("blaargh!!!")) | |
let step03 () : Result<int> = Success (3) | |
let result = attempt { | |
let! one = step01 () | |
let! two = step02 () | |
let! three = step03 () | |
return [one; two; three] |> List.sum | |
} | |
printfn "%A" result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let one () : int = 1 | |
let two () : int = 2 | |
//let three () : int = failwith "There is NO three!" | |
let four () : int = 4 | |
let result2 = attempt { | |
let! n1 = (lift0 one) () | |
let! n2 = (lift0 two) () | |
let! n3 = (lift0 three) () // this one will throw and the computation will end here | |
let! n4 = (lift0 four) () | |
return n1 + n2 + n4 // comment out line #8 to see the computation complete until this point | |
} | |
printfn "%A" result2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let scaryAdd5 x = if (x = 0) then failwith "Cannot add zero!" else x + 5 | |
let scaryAdd5M = lift1 scaryAdd5 | |
let result3 = attempt { | |
let! ten = scaryAdd5M 5 | |
let! fifteen = scaryAdd5M ten | |
return fifteen | |
} | |
let result4 = attempt { | |
let! fifteen = result3 // unpack a packed value with a let! assignment... | |
let! twenty = scaryAdd5M fifteen //...and now you can use it! | |
return twenty | |
} | |
printfn "%A" [result3; result4] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Forget about that
lift
definition, it's unnecessary.Bind
seems to missing the try/catch. Yourlift1
is actuallymap
, which you can define generically in terms of bind+return thus keeping things simpler.