WIP: Validation CE Builder
See original GitHub issueDescription
Not directly related to https://github.com/fsprojects/FSharpPlus/issues/388
But more about the newly released .NET + F# 5.0. The idea would be to provide a dedicated CE builder for validation types supporting the and!
keyword.
Sources:
- https://devblogs.microsoft.com/dotnet/announcing-f-5/#applicative-computation-expressions
- https://gist.githubusercontent.com/cartermp/8540e3fb1edf647f3c7ee8e4352c5941/raw/0c6893a68499499eca517118d3db80c379fc8799/fs5-applicatives.fsx
// First, define a 'zip' function
module Result =
let zip x1 x2 =
match x1,x2 with
| Ok x1res, Ok x2res -> Ok (x1res, x2res)
| Error e, _ -> Error e
| _, Error e -> Error e
// Next, define a builder with 'MergeSources' and 'BindReturn'
type ResultBuilder() =
member _.MergeSources(t1: Result<'T,'U>, t2: Result<'T1,'U>) = Result.zip t1 t2
member _.BindReturn(x: Result<'T,'U>, f) = Result.map f x
let result = ResultBuilder()
let run r1 r2 r3 =
// And here is our applicative!
let res1: Result<int, string> =
result {
let! a = r1
and! b = r2
and! c = r3
return a + b - c
}
match res1 with
| Ok x -> printfn "%s is: %d" (nameof res1) x
| Error e -> printfn "%s is: %s" (nameof res1) e
let printApplicatives () =
let r1 = Ok 2
let r2 = Ok 3 // Error "fail!"
let r3 = Ok 4
run r1 r2 r3
run r1 (Error "failure!") r3
Repro steps
Please provide the steps required to reproduce the problem
let runValidations v1 v2 v3 =
let val1 =
validation {
let! a = v1
and! b = v2
and! c = v3
return a + b - c
}
match val1 with
| Success s -> printfn "%A is: %A" (nameof val1) s
| Failure f -> printfn "%A is: %A" (nameof val1) f
let printValidations () =
let r1 = Validation<string list, int32>.Success 2
let r2 = Validation<string list, int32>.Success 3
let r3 = Validation<string list, int32>.Success 4
runValidations r1 r2 r3
runValidations
r1
(Validation<string list, int32>.Failure [ "Meow 1" ])
(Validation<string list, int32>.Failure [ "Meow 2" ])
[<EntryPoint>]
let main _ =
printValidations()
0
- Step B
Expected behavior
validation
CE builder should be defined and the output of the program should be:
"val1" is: 1
"val1" is: ["Meow 1"; "Meow 2"]
Actual behavior
The value or constructor 'validation' is not defined.
Known workarounds
open FSharpPlus.Data
module Result =
let zip r1 r2 =
match r1, r2 with
| Ok o1, Ok o2 -> Ok (o1, o2)
| Error e1, _ -> Error e1
| _, Error e2 -> Error e2
// Next, define a builder with 'MergeSources' and 'BindReturn'
type ResultBuilder() =
member _.MergeSources(t1: Result<'T,'U>, t2: Result<'T1,'U>) = Result.zip t1 t2
member _.BindReturn(x: Result<'T,'U>, f) = Result.map f x
module Validation =
let zip x1 x2 =
match (x1, x2) with
| Success s1, Success s2 -> Success (s1, s2)
| Failure f1, Success _ -> Failure f1
| Success _, Failure f2 -> Failure f2
| Failure f1, Failure f2 -> Failure (f1 @ f2)
type ValidationBuilder() =
member _.MergeSources(t1, t2) = Validation.zip t1 t2
member _.BindReturn(x, f) = Validation.map f x
member _.Bind(x, f) = Validation.bind f x
let result = ResultBuilder()
let validation = ValidationBuilder()
let runResults r1 r2 r3 =
// And here is our applicative!
let res1: Result<int, string> =
result {
let! a = r1
and! b = r2
and! c = r3
return a + b - c
}
match res1 with
| Ok o -> printfn "%A is: %A" (nameof res1) o
| Error e -> printfn "%A is: %A" (nameof res1) e
let runValidations v1 v2 v3 =
let val1 =
validation {
let! a = v1
and! b = v2
and! c = v3
return a + b - c
}
match val1 with
| Success s -> printfn "%A is: %A" (nameof val1) s
| Failure f -> printfn "%A is: %A" (nameof val1) f
let printResults () =
let r1 = Ok 2
let r2 = Ok 3
let r3 = Ok 4
runResults r1 r2 r3
runResults r1 (Error "failure!") r3
let printValidations () =
let r1 = Validation<string list, int32>.Success 2
let r2 = Validation<string list, int32>.Success 3
let r3 = Validation<string list, int32>.Success 4
runValidations r1 r2 r3
runValidations
r1
(Validation<string list, int32>.Failure [ "Meow 1" ])
(Validation<string list, int32>.Failure [ "Meow 2" ])
[<EntryPoint>]
let main _ =
printResults()
printValidations()
0
Output:
"res1" is: 1
"res1" is: "failure!"
"val1" is: 1
"val1" is: ["Meow 1"; "Meow 2"]
Related information
- Operating system: Windows 10 professional
- Branch:
master
- .NET Runtime, CoreCLR or Mono Version: .NET 5.0 + F# 5.0 (lang preview enabled)
- Performance information, links to performance testing scripts
Issue Analytics
- State:
- Created 3 years ago
- Comments:11 (7 by maintainers)
Top Results From Across the Web
The WIP:Validate Push Components At WIP Completion ...
Oracle Work in Process - Version 12.2.8 and later: The WIP:Validate Push Components At WIP Completion Profile Option Is Not Working ...
Read more >ProjectWise: Project Delivery
Bentley Infrastructure Cloud. Powered by iTwin. Manage and visualize project, construction, or asset information in 2D, 3D, ...
Read more >Problem with Applicative CEs and 'Zero' · Issue #10379
1 reaction. Sorry, something went wrong. @gusty gusty mentioned this issue on Jul 8, 2021. WIP: Validation CE Builder fsprojects/FSharpPlus#397.
Read more >WIP Validation in Blazor Kanban Component
WIP Validation in Blazor Kanban Component. 15 Dec 202210 minutes to read. Validate particular column using the MinCount or MaxCount properties.
Read more >Configure WIP Lane Limit
You can set a limit to the number of cards added to a lane. If the limit is not set, any number of...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Yes, that’s the plan, either incorporate it in
monad
or create a separateapplicative
CE.We started with the former but we found an F# bug which seems it will be solved soon.
Therefore we felt it was safer to wait until that bug is solved so we can evaluate properly which solution is the best, in the meantime adding the
BindReturn
method by hand should be the way to go.Fyi, this is what we have been using at my company for the past couple of months or so: