This is our second blog post in a series of posts about using F# to write simpler, safer, production-quality code. Read the first part here.
One of the most surprising parts of F# is the way it handles functions. Basically, each function in F# always takes one input parameter and gives one output value. They are basically functions in the mathematical sense, transforming one input type to one output type.
Function signatures in F# are shown in this format:
print: int -> string
In this case,
That being said, code like this is perfectly fine:
let add a b = a + b // This works add 3 4 -> 7
If you look at the function signature of
add, it will be something strange like:
add: int -> int -> int
This was greek to me at first. I started to understand it after some research. In this case,
add isn’t a function that takes two numbers and returns their sum. It’s a function that has one input (the first integer) and returns another function. This (returned) function takes one input value (the second integer) and returns the sum of the two integers.
add with two arguments results in two function evaluations.
add 2 3 -> 5 // This is the same as ((add 2) 3) -> 5
This means you can call
add with only one argument.
let increment = add 1 increment: int -> int
You can now use
increment as if it’s a normal function that you defined yourself.
increment 4 -> 5
Sidenote: This naturally leads to a style of programming where you always keep the most important argument (usually the main data structure that you give as the input) to any function as its last argument. It makes function composition much easier. Pipelining is another good reason to do this!
If you ever see a function like this, you’re probably doing it wrong:
let add (a, b) = a + b
This basically says that
add is a function that takes one Tuple of two ints and returns another int. Make sure that when you do write code like this, you mean to do it and you’re not writing it by accident; just because you’re used to putting function arguments in brackets!
This can be a great way to encapsulate components and hide unnecessary implementation details. Lets look at an actual use case:
/// User Validator requires `userType` as an argument let userValidator userType user = // Internal validation rules for the user object /// You can *fix* the `userType` to `NormalUser` like so: let normalUserValidator = userValidator UserType.NormalUser /// Your controller or view codebase only uses the wrapped validator if normalUserValidator currentUser then "Do Something with valid user" else "The normal user is invalid"
This can be used to implement a lot of ‘patterns’ that are quite complex in a non-functional language. It is a natural way to implement decorators, or do dependency injection, for example.
You should watch this talk by Jon Carmack where he discusses his experiments with Haskell; he talks about using a similar technique of passing around partially applied functions to manage game state. Interesting stuff!
Feel free to reach out to me if you have any questions regarding F#. You can email me at ankit (at) cleartax.in. By the way, ClearTax is hiring! You should really join our team if you want to work with F# 🙂