# Eliminating `if` from F#

Recently I was asked by a colleague if there were a better way to write a specific method this colleague was using. It was a simple method which called a couple other methods and returned a value from them. Essentially, if two conditions met specific criteria, call one of four other methods. Oh, and it was in F#.

Naturally, as C-style programmers it's easy for us to use `if` or `switch` to do what we want, but for some reason when we look at functional languages we cannot seem to reason how we should replace these two constructs with `match`. It must be trivial, right? We must be missing some silly detail. That's not entirely true. We're not missing anything trivial, we're just not being creative enough.

Functional languages like F# bear the advantage of being very verbose about what's going on. They're also great at implicitly typing things, and making a function read as a mathematical expression. I bolded that for a reason: if we begin to look at our code as a mathematical expression instead of code, we will hopefully see what we're missing.

Let's look at a much reduced sample of the code we were working with:

``````type ThingType =
Left = 0
| Right = 1

member private this.methodLeftOne =
true

member private this.methodRightOne =
false

member private this.methodLeftTwo =
false

member private this.methodRightTwo =
true

member this.MatchAndIf var thingType =
match var with
| 1 -> if thingType = ThingType.Left then this.methodLeftOne else this.methodRightOne
| 2 -> if thingType = ThingType.Left then this.methodLeftTwo else this.methodRightTwo
| _ -> false
``````

My colleague was calling the `MatchAndIf` function which was to return a boolean value from the two parameters. The code in the other four methods was a bit more complex, but I've simplified it here so we can see how things will turn out.

So, we're looking at a pretty simple bit of code: if `var` and `thingType` are `1` and `ThingType.Left` respectively, return `methodLeftOne`, if they're `1` and any other `ThingType` value, return `this.methodRightOne`, etc. Pretty easy to follow.

We have a slight inconsistency here, however. If `thingType` is set to a non-valid value, then unexpected (well, unintended) things can happen. This is not so ideal. To fix it with this code would be a mess, now we would have `if ... then ... else if ... then ... else ...`. Sure, that does what we want, but it's really ugly for F#.

## Nested `match`

So, the first thing we might think of to rewrite it is to use a nested `match`. Alright, easy enough, replace the inner `if` with a `match`.

``````member this.NestedMatch var thingType =
match var with
| 1 ->
match thingType with
| ThingType.Left -> this.methodLeftOne
| _ -> this.methodRightOne
| 2 ->
match thingType with
| ThingType.Left -> this.methodLeftTwo
| _ -> this.methodRightTwo
| _ -> false
``````

This is obviously more F#-like. It gives us a lot more peace-of-mind, right? But we didn't fix the issue above, so let's do that.

``````member this.NestedMatchFixed var thingType =
match var with
| 1 ->
match thingType with
| ThingType.Left -> this.methodLeftOne
| ThingType.Right -> this.methodRightOne
| _ -> false
| 2 ->
match thingType with
| ThingType.Left -> this.methodLeftTwo
| ThingType.Right -> this.methodRightTwo
| _ -> false
| _ -> false
``````

Wait a minute, why do we need three default (`_`) cases? Ah, right, because if `1` or `2` are matched, they won't fall through to the default case, and F# will get very upset if we omit it and implicitly return `false`. (That's not always a bad thing.)

## Tuple `match`

Well, we might think to ourselves "I can just match on a `Tuple` instead." Indeed that's true, let's see how that looks.

``````member this.TupleMatch var thingType =
match (var, thingType) with
| (1, ThingType.Left) -> this.methodLeftOne
| (1, ThingType.Right) -> this.methodRightOne
| (2, ThingType.Left) -> this.methodLeftTwo
| (2, ThingType.Right) -> this.methodRightTwo
| _ -> false
``````

Alright, that's not bad. We've gotten a lot closer to our goal. But now we have things knowing about things they shouldn't. The `TupleMatch` method does too many things inside it. It's looking for a `var` of `1` or `2` and a `ThingType`.

## Finally Isolating Everything

The only other thing we can do to fix this (which I can tell you is the best option based on the context of what code I had) is to check `thingType` in our `Match` method, and pipe `var` to our `methodLeft` or `methodRight` method (whichever is appropriate).

``````member private this.methodLeft var =
match var with
| 1 -> true
| _ -> false

member private this.methodRight var =
match var with
| 2 -> true
| _ -> false

member this.FinalMatch var thingType =
match thingType with
| ThingType.Left -> var |> this.methodLeft
| ThingType.Right -> var |> this.methodRight
| _ -> false
``````

Now each method is only responsible for checking and reporting the parts it cares about. We complied with SRP and we kept it entirely functional. Each method is responsible for looking at only the code it cares about, it's not worried about what the next method down the chain is doing.