Skip to content

Commit

Permalink
Merge pull request #426 from gdziadkiewicz/add_inlining_for_CEs
Browse files Browse the repository at this point in the history
Add inlining for Result
  • Loading branch information
gdziadkiewicz authored Oct 31, 2022
2 parents be522d1 + 05f1aa3 commit 91046dc
Showing 1 changed file with 26 additions and 29 deletions.
55 changes: 26 additions & 29 deletions src/FSharpx.Extras/ComputationExpressions/Result.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ module Result =
open FSharpx.Collections

/// Inject a value into the Result type
let returnM = Ok
let inline returnM x = Ok x
/// If Result is Ok, return its value.
/// Otherwise throw ArgumentException.
let get =
function
let inline get x =
match x with
| Ok a -> a
| Error e -> invalidArg "result" (sprintf "The result value was Error '%A'" e)
/// Wraps a function, encapsulates any exception thrown within to a Result
let inline protect f x =
let inline protect ([<InlineIfLambda>]f) x =
try
Ok (f x)
with e -> Error e
Expand All @@ -21,7 +21,7 @@ module Result =
let inline cast (o: obj) = protect unbox o

/// Sequential application
let ap x f =
let inline ap x f =
match f,x with
| Ok f , Ok x -> Ok (f x)
| Error e , _ -> Error e
Expand Down Expand Up @@ -60,19 +60,19 @@ module Result =
/// Maps both parts of a Choice.
/// Applies the first function if Result is Ok.
/// Otherwise applies the second function
let inline bimap f1 f2 =
function
let inline bimap ([<InlineIfLambda>] f1) ([<InlineIfLambda>] f2) x =
match x with
| Ok x -> Ok (f1 x)
| Error x -> Error (f2 x)

/// If Some value, returns Ok value. Otherwise, returns the supplied default value.
let ofOption o =
let inline ofOption o =
function
| Some a -> Ok a
| None -> Error o

/// If Some value, returns Ok value. Otherwise, returns the supplied default value from a function.
let ofOptionF f =
let inline ofOptionF ([<InlineIfLambda>] f) =
function
| Some a -> Ok a
| None -> Error (f())
Expand All @@ -82,51 +82,48 @@ module Result =
List.foldBack cons s (returnM [])

/// Gets the value of result if the result is Ok, otherwise evaluates f and returns the result.
let defaultWith (f:unit->'a) (result:Result<'a,_>) : 'a =
let inline defaultWith ([<InlineIfLambda>] f:unit->'a) (result:Result<'a,_>) : 'a =
match result with
| Ok x -> x
| Error _ -> f()

/// Gets the value of result if the result is Ok, otherwise returns the specified default value v.
let defaultValue (v:'a) (result:Result<'a,_>) : 'a =
let inline defaultValue (v:'a) (result:Result<'a,_>) : 'a =
match result with
| Ok x -> x
| Error _ -> v

/// Case analysis for the Result type. If the value is Ok x, apply the first function to x; if it is Error e, apply the second function to e.
let inline either (f:'a->'c) (h:'b->'c) (result: Result<'a,'b>) : 'c =
let inline either ([<InlineIfLambda>] f:'a->'c) ([<InlineIfLambda>] h:'b->'c) (result: Result<'a,'b>) : 'c =
match result with
| Ok x -> f x
| Error e -> h e

type ResultBuilder() =
member _.Return x = Ok x
member _.Bind (m, f) = Result.bind f m
member _.ReturnFrom m = m
member _.Zero() = Ok ()
member _.Delay f = f
member _.Run f = f()

member this.TryWith(m, h) =
member inline _.Return x = Ok x
member inline _.Bind (m, [<InlineIfLambda>] f) = Result.bind f m
member inline _.ReturnFrom m = m
member inline _.Zero() = Ok ()
member inline _.Delay f = f
member inline _.Run ([<InlineIfLambda>] f) = f()

member inline this.TryWith(m, [<InlineIfLambda>] h) =
try this.ReturnFrom(m)
with e -> h e

member this.TryFinally(m, compensation) =
member inline this.TryFinally(m, [<InlineIfLambda>] compensation) =
try this.ReturnFrom(m)
finally compensation()

member this.Using(res:#System.IDisposable, body) =
member inline this.Using(res:#System.IDisposable, [<InlineIfLambda>] body) =
this.TryFinally(body res, fun () -> if not (isNull (box res)) then res.Dispose())


member this.While(guard, f) =
if not (guard()) then
this.Zero()
else
member inline this.While([<InlineIfLambda>] guard, [<InlineIfLambda>] f) =
while guard() do
f() |> ignore
this.While(guard, f)
this.Zero()

member this.For(sequence:seq<_>, body) =
member inline this.For(sequence:seq<_>, [<InlineIfLambda>] body) =
this.Using(sequence.GetEnumerator(),
fun enum -> this.While(enum.MoveNext, this.Delay(fun () -> body enum.Current)))

Expand Down

0 comments on commit 91046dc

Please sign in to comment.