# String Calculator Kata in F# - fall of exceptions

Today we are going to implement handling negative values and values that are greater than 1000. It's step 5 and 6 from the kata description:
* calling Add with a negative number will throw an exception "negatives not allowed" - and return passed negative values
* ignore numbers greater than 1000, so 1002 + 1 equals 1

This is a third part of a series:  

1.  [String Calculator Kata](https://blog.ciechowski.net/string-calculator-kata-in-f ) 
2.  [Another encounter](https://blog.ciechowski.net/string-calculator-kata-in-f-another-encounter)
3. [Fall of exceptions](https://blog.ciechowski.net/string-calculator-kata-in-f-fall-of-exceptions) (this one)
4. [Happy end](https://blog.ciechowski.net/string-calculator-kata-in-f-happy-end)


Finally, we can try to handle exceptions in a functional way.  
Spoiler alert! There won't be any exceptions.

Since last time we have an elegant pipeline. 
```
let sumNumbers = parseInput >> convertToNumbers >> Seq.sum
```
Because we use composition, we can pass the data from one function to another. Additionally, it makes it open for extension by adding a new function to our current flow.

Back to handling negative values, we start with a test:
```
[<Fact>]
let ``Cannot add negative values`` =
  let result = Add "-3, 1"
  Assert.Equal(Error "-3", result)
```
When adding a negative value, we expect that we get that value back wrapped in an `Error.`
That strange prefix inside the assertion can be surprising, right?
It means an error, obviously, but what kind of error is this?  
That is, my friends, an elegant way of handling exceptions. Without throwing an exception at all!  

Take a look at Add function:
```
let Add (numbers: string): Result<int, string> =
    sumWithFilter numbers
```
Notice the return type of the function. From `int`, it turned to `Result<int,string>.`  
Why? Because now it can return one of two values. An integer when everything went fine or a string when we tried to add negative values. 

Stop for a moment here. What's wrong with throwing an exception? Everyone does that all the time! Why can't we follow the same path?

But is it an exceptional situation? I don't think so. It's a part of our domain!
We know that we will deal with a negative value. Also, we know how to handle such a case. Let's make it explicit with the `Result` type.  
Using this approach, we make it evident that our function can have two mutually exclusive outputs - one for success and an error.
You can read more on this on a great [@ScottWlaschin](https://twitter.com/ScottWlaschin) [blog](https://fsharpforfunandprofit.com/posts/recipe-part2/
).  
Having the `Result` behind us, we can attach to our pipeline a filter for negative values like so:
```
let sumWithFilter =  
    parseInput  
    >> convertToNumbers  
    >> findNegativeValues  
    >> sum
```
and findNegativeValues implementation:
```
let findNegativeValues (numbers: Numbers) =
    let negativeValues = Array.filter (fun x -> x < 0) numbers
    match Array.isEmpty negativeValues with
    | true -> Ok numbers
    | false -> Error negativeValues
```
That is the place where we elevate our pipeline into the `Result` world.
When we got any negative numbers in the input, we return an `Error` and said values. In the other case, we produce an `OK` of input.

Because of elevating to the `Result` land, we have to modify our sum function:
```
let sum (numbersWithNegatives: Result<Numbers, int[]>) =
    match numbersWithNegatives with
    | Ok n -> Ok (Seq.sum n)
    | Error e -> e |> Array.map string |> String.concat "," |> Error
```
Notice the pattern matching here. If we got only positive values, we return an `OK` of summed numbers. When we got any negative values, we produce an `Error` with concatenated negative values.

This way, we solved the issue with negative values. We didn't use any exceptions but achieved the same result. The critical point is that our `Add` function now returns an `OK` or an `Error`

We have one more thing to do. It's step 6 and ignoring numbers greater than 1000.
This one is relatively easy. We have to filter out any number that is greater than 1000 with this function.
```
let ignoreValuesGreaterThan1000 (numbers: Numbers) =  
    Array.filter (fun x -> x < 1000) numbers
```
And add it to our pipeline.
```
let sumWithFilter =  
    parseInput  
    >> convertToNumbers  
    >> ignoreValuesGreaterThan1000  
    >> findNegativeValues  
    >> sum  
```

Full code is available, as always, on my  [github](https://github.com/jciechowski/StringCalculatorKataFSharp/tree/step-5-and-6).

In the next part, we will implement all three remaining steps.
See you there!


