I am new to everything - F#, programming in general, and this community. I am a mathematician with brief exposure to computer science in my undergrad. I am trying to accomplish some tasks in F# and the "F# Cheat Sheet" exhibits what appears to be three different ways to compose functions without explaining the repetition. Here is the relevant information from the link to see what I mean.
The let keyword also defines named functions.
let negate x = x * -1
let square x = x * x
let print x = printfn "The number is: %d" x
let squareNegateThenPrint x =
print (negate (square x))
Pipe operator |> is used to chain functions and arguments together. Double-backtick identifiers are handy to improve readability especially in unit testing:
let ``square, negate, then print`` x =
x |> square |> negate |> print
Composition operator >> is used to compose functions:
let squareNegateThenPrint' =
square >> negate >> print
By inspection and by playing in VS F# interactive with the functions:
- squareNegateThenPrint x
- ``square, negate, then print'' x
- squareNegateThenPrint'
it appears that this is a list of 3 ways to accomplish the exact same thing, are there any nuances here? I am convinced that given the same int they will all return the same int, but how about beyond that? What am I not seeing? What are advantages and disadvantages of each of the three methods?
2 and 3 both use 'operators' and 1 seems to be the usual 'mathematical' way of composing functions to make a new function from old functions. I suspect option 3 to be truly equivalent to 1 (in the sense that the >> operator is defined so that square >> negate >> print is actually computed as print (negate (square x)) but the code benefits in readability since you see the function names in the order they happen instead of reverse order with the usual mathematical notation, and defining this way saves you a keystroke or two since you don't have to include the x at the end of the function name since the >> operator probably makes the left function automatically inherit dependence on the variable of the function on the right, without explicit reference to the variable.
But then how does the piping method play into this? Is the piping operator a more general operator that just so happens to work for function composition?
Also, I did google quite a bit and try to read the documentation before posting but I was not getting anywhere. I am sure if I just moved on and kept learning the language, sometime in the next year I would understand the differences. But I am also confident someone on here can expedite that process and explain or provide some nice examples. Lastly, I am not proficient in C#, or really any other language (except mathematics) so explanations for a total noob and not just an f# noob appreciated. Thanks!