Skip to content

Instantly share code, notes, and snippets.

@michael-newton-15below
Last active December 11, 2015 05:09
Show Gist options
  • Save michael-newton-15below/4550496 to your computer and use it in GitHub Desktop.
Save michael-newton-15below/4550496 to your computer and use it in GitHub Desktop.
Decompose error handling computation expression with use
// Our basic cexpr, fully sugared
let calculate input =
audit {
use! thing = Some input
return (possibleGoWrongThing thing)
}
// Rest of this might not be valid f# code at every step.
// Expanding using documentation at http://msdn.microsoft.com/en-us/library/dd233182.aspx
// Step one: Delay
let calculate input =
audit.Delay(fun () ->
audit {
use! thing = Some input
return (possibleGoWrongThing thing)
})
// Step two: First use and bind
let calculate input =
audit.Delay(fun () ->
audit.Bind(Some input, fun thing ->
audit.Using(thing, fun thing ->
audit {
return (possibleGoWrongThing thing)
})))
// Step three: Return
let calculate input =
audit.Delay(fun () ->
audit.Bind(Some input, fun thing ->
audit.Using(thing, fun thing ->
audit.Return (possibleGoWrongThing thing)
)))
// Step four: Expand Bind
let calculate input =
audit.Delay(fun () ->
match Some input with
| None -> None
| Some thing ->
try
fun thing ->
audit.Using(thing, fun thing ->
audit.Return (possibleGoWrongThing thing)
with
| _ as e ->
printfn "%A" e
None)
// Step five: Expand Using
let calculate input =
audit.Delay(fun () ->
match Some input with
| None -> None
| Some thing ->
try
fun thing ->
audit.TryFinally(
audit.Return (possibleGoWrongThing thing),
fun () -> thing.Dispose())
with
| _ as e ->
printfn "%A" e
None)
// Step six: Expand TryFinally <-- This is the step where I made my mistake. You can't
// expand this code out like this, as possibleGoWrongThing is evaluated when it becomes
// a needed method parameter and so throws before it ever gets wrapped in the try.. finally
// block.
let calculate input =
audit.Delay(fun () ->
match Some input with
| None -> None
| Some thing ->
try
fun thing ->
try audit.ReturnFrom(audit.Return(possibleGoWrongThing thing))
finally thing.Dispose()
with
| _ as e ->
printfn "%A" e
None)
// Step seven: Expand Return/ReturnFrom
let calculate input =
audit.Delay(fun () ->
match Some input with
| None -> None
| Some thing ->
try
fun thing ->
try Some (possibleGoWrongThing thing)
finally thing.Dispose()
with
| _ as e ->
printfn "%A" e
None)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment