FSharpx: Validating with applicative functors
I've been recently interested in Functors, applicatives and monads, especially in context of complex validation.
FSharpx has a validation module (among many other wonderful features). I've played with it a bit:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open FSharpx.Choice | |
open FSharpx.Validation | |
open FSharpx.Collections | |
open System | |
// generic validator which returns Success if given predicate succeeds, otherwise Failure of NonEmptyList of errors | |
let validator pred error value = | |
if pred value then Choice1Of2 value | |
else Choice2Of2 (NonEmptyList.singleton error) | |
// some simple validators | |
let notEqual x = validator ((<>) x) <| sprintf "should not equal to %d" x | |
let evenNumber = validator (fun x -> x % 2 = 0) "should be even" | |
// a more complex validator made by combining a couple of simpler ones | |
let validateNumber n = | |
returnM n | |
<* evenNumber n | |
<* notEqual 3 n | |
let printRes res = | |
match res with | |
| Success n -> printfn "%A" n | |
| Failure errors -> errors |> String.concat ", " |> printfn "%s" | |
// test | |
[-5..5] |> List.iter (fun x -> (x, validateNumber x) ||> print) | |
results: | |
-5 | should be even | |
-4 | -4 | |
-3 | should be even | |
-2 | -2 | |
-1 | should be even | |
0 | 0 | |
1 | should be even | |
2 | 2 | |
3 | should be even, should not equal to 3 | |
4 | 4 | |
5 | should be even |
Applicatives can be combined using several operators and functions, for example all following functions are equivalent:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let validateNumber n = | |
returnM n | |
<* evenNumber n | |
<* notEqual 3 n | |
let validateNumber' n = | |
returnM (fun _ _ -> n) | |
<*> evenNumber n | |
<*> notEqual 3 n | |
let validateNumber'' n = | |
returnM (konst2 n) | |
<*> evenNumber n | |
<*> notEqual 3 n | |
let validateNumber''' n = | |
konst2 n | |
<!> evenNumber n | |
<*> notEqual 3 n | |
let validateNumber'''' n = | |
returnM (konst2 n) | |
|> ap (evenNumber n) | |
|> ap (notEqual 3 n) | |
let validateNumber''''' n = | |
konst n | |
<!> (evenNumber >=> notEqual 3) n | |
let validateNumber'''''' n = | |
returnM n <* sequence [evenNumber n; notEqual 3 n] |
Comments
as a result of massive selection of supplies used in tag heuer aquaracer creating, it doesn't matter what type they come in. This article was written to help you to find these solutions.
Also visit my blog ... tag heuer aquaracer grande date
Also visit my web-site; Tag And Heuer