Reputation: 9472
I've been working my way through this article on ROP, and have reached the section "Converting simple functions to the railway-oriented programming model" where he explains how to fit other kinds of functions into the model.
He gave the example of wanting to clean an email address (function name different as I'm English!)...
let cleanEmail person =
printfn "Cleaning email for \"%s\"" person.Name
let newPerson = { person with Email = person.Email.Trim().ToLower() }
printfn " email is now \"%s\"" newPerson.Email
newPerson
I added some printfn to see what was happening. This function works fine, in that if I pass it an input with an email that has uppercase letters and/or leading/trailing blanks, the output is a value with a clean, lowercase email address...
let shouter = { Name = "Jim"; Email = " [email protected] "}
cleanEmail shouter
Gives the output...
Cleaning email for "Jim"
email is now "[email protected]"
val it : Request = {Name = "Jim";
Email = "[email protected]";}
However, if I wrap this function in a switch, and insert it into the chain of validation functions, the original email address is used. For example, with validation functions like this...
let validateNameNotBlank person =
printfn "Validating name not blank for \"%s\"" person.Name
if person.Name = "" then Failure "Name must not be blank"
else Success person
...an operator like this...
let (>=>) switch1 switch2 input =
match switch1 input with
| Success s -> switch2 input
| Failure f -> Failure f
...and bound together like this...
let validate =
validateNameNotBlank
>=> validateNameLength
>=> switch cleanEmail
>=> validateEmail
...then when I pass shouter in, I get the following out...
Validating name not blank for "Jim"
Validating name length for "Jim"
Cleaning email for "Jim"
email is now "[email protected]"
Validating email for "Jim" ( [email protected] )
val it : Result<Request,string> = Success {Name = "Jim";
Email = " [email protected] ";}
You can see from the printfn I put in that the cleanEmail function is cleaning the email, but the output shows that the original email is passed to the next function in the chain.
What have I missed here?
Upvotes: 3
Views: 142
Reputation: 25526
If you look at the article, the operator has the definition
let (>=>) switch1 switch2 x =
match switch1 x with
| Success s -> switch2 s
| Failure f -> Failure f
which when correctly translated to your variables is:
let (>=>) switch1 switch2 input =
match switch1 input with
| Success s -> switch2 s
| Failure f -> Failure f
You never actually use the s
from the Success
so the same input just keeps getting passed through.
A close examination of the type of >=>
would have revealed this problem as yours would have given the same type to switch1
and switch2
when they should have different types.
Upvotes: 5