Skip to content

Instantly share code, notes, and snippets.

@johnazariah
Last active August 29, 2015 14:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnazariah/63a88b2e13c06799a871 to your computer and use it in GitHub Desktop.
Save johnazariah/63a88b2e13c06799a871 to your computer and use it in GitHub Desktop.
Attempt computation expression
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 ()
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
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
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]
@mausch
Copy link

mausch commented Mar 16, 2015

Forget about that lift definition, it's unnecessary. Bind seems to missing the try/catch. Your lift1 is actually map, which you can define generically in terms of bind+return thus keeping things simpler.

@johnazariah
Copy link
Author

@maush ok I'll push the try-catch into Bind and refactor. Thanks for your suggestion :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment