In addition to @JoshuaFox's answer, one answer to your other question about why not pass all parameters in a single go is that it often makes code repetitive and can add a lot of boilerplate where it isn't really needed.
I have a small web app written in F# that works on several different platforms. I have a config file that provides values for each specific platform. At runtime I get those values from the config file and have functions like this:
let private supptFunc (p1: string) (p2: string) (p3: string) : string = ...
...
// Partially apply parameters from config file to create a simpler
// function in the rest of the code
let externaFn1 = supptFunc (<get v1 from config file>) (<get v2 from config file>)
This makes externalFn1
a function that takes a string and returns a string. So, in the rest of my code I only call externaFn1
with a single parameter (p3
) which I get from the requests.
In this way I implement supptFunc
in terms of the parameters it needs to do the job and never worry about where they come from. I don't have to read a config file inside the code or store the values in a list or map somewhere. They are always passed in.
But I don't have to make those values available where ever the function may be needed. I have simply created a useful function that I expose to the rest of my code that has those values 'baked in' for the current platform. All of the rest of the codebase simply uses that exposed function with only the parameters they have and need.
So, now I can test supportFunc
as a function that always takes all the parameters it needs and can provide any parameters I want at test time to check out its behavior under any circumstances I choose. But I don't require all callers to provide everything supportFunc
needs since it isn't necessarily their responsibility to hold on to all of this information.
This isn't the only use case for partial application, but the fact that F# automatically curries functions makes it a simple way to keep your code cleaner and simpler.