Skip to content

Commit e68bb0f

Browse files
committed
Adds bind CE and bind same benchmarks
1 parent 8ae79c3 commit e68bb0f

File tree

3 files changed

+154
-17
lines changed

3 files changed

+154
-17
lines changed

benchmarks/Benchmarks.fs

Lines changed: 150 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ open BenchmarkDotNet.Attributes
77

88
let okF x = x + 2
99
let errorF x = x - 4
10-
1110
let add x y = x + y
1211

1312
module Result =
13+
14+
// let inline (|>>) ([<InlineIfLambda>] v : _ -> _) ([<InlineIfLambda>] f : _ -> _) = f v
1415
module Normal =
1516

1617
let either okF errorF x =
@@ -38,13 +39,9 @@ module Result =
3839
let eitherMap (okF) (errorF) x =
3940
either (fun x -> x |> okF |> Result.Ok) (fun y -> y |> errorF |> Result.Error) x
4041

41-
let bind (f) x =
42-
match x with
43-
| Ok x -> f x
44-
| Error e -> Error e
4542
let apply (f) x =
46-
bind (fun f' ->
47-
bind (fun x -> f' x |> Ok) x) f
43+
Result.bind (fun f' ->
44+
Result.bind (fun x -> f' x |> Ok) x) f
4845
let map2 (f) x y =
4946
(apply (apply (Ok f) x) y)
5047

@@ -174,7 +171,23 @@ module Result =
174171
| Error e, _ -> Error e
175172
| _ , Error e -> Error e
176173

177-
let inline map2 ([<InlineIfLambda>] f) x y =
174+
let inline map ([<InlineIfLambda>] mapper : 'ok -> 'ok2) value =
175+
match value with
176+
| Ok x -> Ok(mapper x)
177+
| Error e -> Error e
178+
179+
180+
let inline bindSame ([<InlineIfLambda>] binder: 'ok -> Result<'ok, 'err>) value =
181+
match value with
182+
| Ok x -> binder x
183+
| Error _ -> value
184+
185+
let inline bind ([<InlineIfLambda>] binder: 'ok -> Result<'ok2, 'err>) value =
186+
match value with
187+
| Ok x -> binder x
188+
| Error e -> Error e
189+
190+
let inline map2 ([<InlineIfLambda>] f : 'a -> 'b -> 'c) x y =
178191
match x, y with
179192
| Ok x, Ok y -> f x y |> Ok
180193
| Error e as z, _ -> Error e
@@ -191,7 +204,7 @@ type EitherMapBenchmarks () =
191204
member this.Result_Normal_NoComposition_EitherMap () =
192205
Ok 4
193206
|> Result.Normal.NoComposition.eitherMap okF errorF
194-
207+
195208
[<Benchmark>]
196209
member this.Result_Inlined_EitherMap () =
197210
Ok 4
@@ -224,6 +237,133 @@ type EitherMapBenchmarks () =
224237
|> Result.Alt.InlinedLambda.eitherMap okF errorF
225238

226239

240+
type ResultBuilder() =
241+
member __.Return(value: 'T) : Result<'T, 'TError> = Ok value
242+
243+
// member inline __.ReturnFrom(result: Result<'T, 'TError>) : Result<'T, 'TError> = result
244+
245+
member this.Zero() : Result<unit, 'TError> = this.Return()
246+
247+
member __.Bind(result: Result<'T, 'TError>, binder: 'T -> Result<'U, 'TError>) : Result<'U, 'TError> =
248+
Result.bind binder result
249+
250+
251+
type ResultBuilderInlined() =
252+
member inline __.Return(value: 'T) : Result<'T, 'TError> = Ok value
253+
254+
// member inline __.ReturnFrom(result: Result<'T, 'TError>) : Result<'T, 'TError> = result
255+
256+
member inline this.Zero() : Result<unit, 'TError> = this.Return()
257+
258+
member inline __.Bind(result: Result<'T, 'TError>, binder: 'T -> Result<'U, 'TError>) : Result<'U, 'TError> =
259+
Result.Inlined.bind binder result
260+
261+
type ResultBuilderInlinedLambda() =
262+
member inline __.Return(value: 'T) : Result<'T, 'TError> = Ok value
263+
264+
member inline this.Zero() : Result<unit, 'TError> = this.Return()
265+
266+
member inline __.Bind(result: Result<'T, 'TError>, [<InlineIfLambda>] binder: 'T -> Result<'T, 'TError>) : Result<'T, 'TError> =
267+
Result.Alt.InlinedLambda.bindSame binder result
268+
269+
[<AutoOpen>]
270+
module ResultCEExtensions =
271+
type ResultBuilderInlinedLambda with
272+
member inline __.Bind(result: Result<'T, 'TError>, [<InlineIfLambda>]binder: 'T -> Result<'U, 'TError>) : Result<'U, 'TError> =
273+
Result.Alt.InlinedLambda.bind binder result
274+
275+
let result = ResultBuilder()
276+
let resultInlined = ResultBuilderInlined()
277+
let resultInlinedLambda = ResultBuilderInlinedLambda()
278+
[<MemoryDiagnoser>]
279+
type MapBenchmarks () =
280+
[<Benchmark(Baseline = true)>]
281+
member this.Result_Normal_Map () =
282+
Result.map (fun x -> x + 2 ) (Ok 1) : Result<_,int>
283+
284+
[<Benchmark>]
285+
member this.Result_Alt_InlinedLambda_Map () =
286+
Result.Alt.InlinedLambda.map (fun x -> x + 2 ) (Ok 1) : Result<_,int>
287+
288+
let runTimes x action =
289+
let results = ResizeArray<_>()
290+
for i=1 to x do
291+
action() |> results.Add
292+
results
293+
294+
[<MemoryDiagnoser>]
295+
type BindSameBenchmarks () =
296+
[<Benchmark(Baseline = true)>]
297+
member this.Result_Alt_InlinedLambda_Bind () : ResizeArray<Result<int,string>> =
298+
runTimes 1000 (fun () -> Result.Alt.InlinedLambda.bind (fun x -> Ok(x + 2) ) (Ok 1) )
299+
[<Benchmark>]
300+
member this.Result_Alt_InlinedLambda_BindSame () : ResizeArray<Result<int,string>> =
301+
runTimes 1000 (fun () -> Result.Alt.InlinedLambda.bindSame (fun x -> Ok(x + 2) ) (Ok 1) )
302+
303+
[<Benchmark>]
304+
member this.Result_Alt_InlinedLambda_Bind_Error () : ResizeArray<Result<int,string>> =
305+
runTimes 1000 (fun () -> Result.Alt.InlinedLambda.bind (fun x -> Ok(x + 2) ) (Error "no"))
306+
[<Benchmark>]
307+
member this.Result_Alt_InlinedLambda_BindSame_Error () : ResizeArray<Result<int,string>> =
308+
runTimes 1000 (fun () -> Result.Alt.InlinedLambda.bindSame (fun x -> Ok(x + 2) ) (Error "no"))
309+
310+
[<MemoryDiagnoser>]
311+
type BindBenchmarks () =
312+
[<Benchmark(Baseline = true)>]
313+
member this.Result_Normal_Bind () =
314+
Result.bind (fun x -> Ok(x + 2) ) (Ok 1) : Result<int,int>
315+
316+
[<Benchmark>]
317+
member this.Result_Alt_InlinedLambda_Bind () =
318+
Result.Alt.InlinedLambda.bind (fun x -> Ok(x + 2) ) (Ok 1) : Result<int,int>
319+
320+
let divide x y =
321+
match y with
322+
| 0 -> Error "Cannot divide by 0"
323+
| _ -> Ok (x/y)
324+
325+
[<MemoryDiagnoser>]
326+
type BindCEBenchmarks () =
327+
[<Benchmark(Baseline = true)>]
328+
member this.Result_Normal_Bind_CE() =
329+
let action () = result {
330+
let! a = Ok 1
331+
let! b = Ok 3
332+
let! c = divide a b
333+
return c
334+
}
335+
action ()
336+
337+
[<Benchmark>]
338+
member this.Result_Alt_Inlined_Bind_CE () =
339+
let action () = resultInlined {
340+
let! a = Ok 1
341+
let! b = Ok 3
342+
let! c = divide a b
343+
return c
344+
}
345+
action ()
346+
[<Benchmark>]
347+
member this.Result_Alt_InlinedLambda_Bind_CE () =
348+
let action () = resultInlinedLambda {
349+
let! a = Ok 1
350+
let! b = Ok 3
351+
let! c = divide a b
352+
return c
353+
}
354+
action ()
355+
356+
[<Benchmark>]
357+
member this.Result_Alt_InlinedLambda_Bind_CE2 () : Result<int,string> =
358+
let action () = resultInlinedLambda {
359+
let! a = Ok 1
360+
let! b = Ok 3.0
361+
let! c = divide a (int b)
362+
return c
363+
}
364+
action ()
365+
366+
227367
[<MemoryDiagnoser>]
228368
type Map2Benchmarks () =
229369

@@ -250,17 +390,11 @@ type Map2Benchmarks () =
250390

251391
[<Benchmark>]
252392
member this.Result_Alt_Map2 () =
253-
254393
Result.Alt.map2 add (Ok 1) (Ok 2) : Result<int,int>
255394
[<Benchmark>]
256395
member this.Result_Alt_Inlined_Map2 () =
257-
258396
Result.Alt.Inlined.map2 add (Ok 1) (Ok 2) : Result<int,int>
259-
260397
[<Benchmark>]
261398
member this.Result_Alt_InlinedLambda_Map2 () =
262399
Result.Alt.InlinedLambda.map2 add (Ok 1) (Ok 2) : Result<int,int>
263-
264-
[<Benchmark>]
265-
member this.Result_Alt_InlinedLambda2_Map2 () =
266-
Result.Alt.InlinedLambda.map2 (fun x y -> x + y) (Ok 1) (Ok 2) : Result<int,int>
400+

benchmarks/Program.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ open benchmarks
55
[<EntryPoint>]
66
let main argv =
77
// BenchmarkRunner.Run<EitherMapBenchmarks>() |> ignore
8-
BenchmarkRunner.Run<Map2Benchmarks>() |> ignore
8+
// BenchmarkRunner.Run<BindCEBenchmarks>() |> ignore
9+
BenchmarkRunner.Run<BindSameBenchmarks>() |> ignore
10+
//
911

1012
0 // return an integer exit code

benchmarks/benchmarks.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFramework>net6.0</TargetFramework>
55
<OutputType>Exe</OutputType>
66
<LangVersion>preview</LangVersion>
7+
<WarnOn>3517</WarnOn>
78
</PropertyGroup>
89
<PropertyGroup>
910
<PlatformTarget>AnyCPU</PlatformTarget>

0 commit comments

Comments
 (0)