@@ -7,10 +7,11 @@ open BenchmarkDotNet.Attributes
7
7
8
8
let okF x = x + 2
9
9
let errorF x = x - 4
10
-
11
10
let add x y = x + y
12
11
13
12
module Result =
13
+
14
+ // let inline (|>>) ([<InlineIfLambda>] v : _ -> _) ([<InlineIfLambda>] f : _ -> _) = f v
14
15
module Normal =
15
16
16
17
let either okF errorF x =
@@ -38,13 +39,9 @@ module Result =
38
39
let eitherMap ( okF ) ( errorF ) x =
39
40
either ( fun x -> x |> okF |> Result.Ok) ( fun y -> y |> errorF |> Result.Error) x
40
41
41
- let bind ( f ) x =
42
- match x with
43
- | Ok x -> f x
44
- | Error e -> Error e
45
42
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
48
45
let map2 ( f ) x y =
49
46
( apply ( apply ( Ok f) x) y)
50
47
@@ -174,7 +171,23 @@ module Result =
174
171
| Error e, _ -> Error e
175
172
| _ , Error e -> Error e
176
173
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 =
178
191
match x, y with
179
192
| Ok x, Ok y -> f x y |> Ok
180
193
| Error e as z, _ -> Error e
@@ -191,7 +204,7 @@ type EitherMapBenchmarks () =
191
204
member this.Result_Normal_NoComposition_EitherMap () =
192
205
Ok 4
193
206
|> Result.Normal.NoComposition.eitherMap okF errorF
194
-
207
+
195
208
[<Benchmark>]
196
209
member this.Result_Inlined_EitherMap () =
197
210
Ok 4
@@ -224,6 +237,133 @@ type EitherMapBenchmarks () =
224
237
|> Result.Alt.InlinedLambda.eitherMap okF errorF
225
238
226
239
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
+
227
367
[<MemoryDiagnoser>]
228
368
type Map2Benchmarks () =
229
369
@@ -250,17 +390,11 @@ type Map2Benchmarks () =
250
390
251
391
[<Benchmark>]
252
392
member this.Result_Alt_Map2 () =
253
-
254
393
Result.Alt.map2 add ( Ok 1 ) ( Ok 2 ) : Result< int, int>
255
394
[<Benchmark>]
256
395
member this.Result_Alt_Inlined_Map2 () =
257
-
258
396
Result.Alt.Inlined.map2 add ( Ok 1 ) ( Ok 2 ) : Result< int, int>
259
-
260
397
[<Benchmark>]
261
398
member this.Result_Alt_InlinedLambda_Map2 () =
262
399
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
+
0 commit comments