# String Calculator Kata in F# - happy end

Our calculator works pretty well so far. We were also able to use a few functional techniques in the process. Railway programming and composition is one of them.

This is a second part of a series:

Today we are going to focus on different types of delimiters:

- a delimiter can be of any length
- user can pass multiple delimiters of any size as an input

We are going to write a bit more code to implement these cases. Furthermore, we will do some domain modeling.

As always, in the beginning, there is a test:

```
[<Fact>]
let ``Delimiter can be of any length`` =
let result = Add "//[***]\n1***2***3"
Assert.Equal(Ok 6, result)
```

The first thing we will do is introduce a new type called DelimiterType

```
type DelimiterType =
| Default
| OneCharacterLong
| MoreThanOneCharacterLong
```

We model our delimiter in a more granular way and explicitly define all available options with this type. Which, in turn, improves our domain.

With the introduction of a different kind of separators, we have to refine our algorithm. Instead of only deciding if a custom delimiter was passed, we now have to recognize its type. We do that with a new function:

```
let findDelimiterType (numbers: Input) =
match numbers.StartsWith "//" with
| false -> Default
| true ->
match numbers.Contains "[" && numbers.Contains "]" with
| false -> OneCharacterLong
| true -> MoreThanOneCharacterLong
```

I'm not satisfied with this approach. This double pattern matching seems clumsy. But I don't know what to do with it, and it works. Refactoring remarks are more than welcome.

It also forces us to add a new case in both extractNumbers and extractDelimiter:

```
let extractNumbers (numbers: Input, delimiterType: DelimiterType) =
match delimiterType with
| Default -> numbers
| OneCharacterLong -> numbers.[4..numbers.Length]
| MoreThanOneCharacterLong ->
let delimiterEnd = numbers.IndexOf "]" + 2
numbers.[delimiterEnd..numbers.Length]
let extractDelimiter (numbers: Input, delimiterType: DelimiterType) =
let defaultDelimiters = [| ","; "\n" |]
match delimiterType with
| Default -> defaultDelimiters
| OneCharacterLong ->
let customDelimiter = [| string numbers.[2] |]
Array.concat [| defaultDelimiters
customDelimiter |]
| MoreThanOneCharacterLong ->
let delimiterStart = numbers.IndexOf "[" + 1
let delimiterEnd = numbers.IndexOf "]" - 1
let delimiter =
[| numbers.[delimiterStart..delimiterEnd] |]
Array.concat [| defaultDelimiters
delimiter |]
```

One more change in parseInput function, where we extract delimiter type:

```
let parseInput (input: Input): InputWithDelimiters =
let delimiterType = findDelimiterType input
let numbers = extractNumbers (input, delimiterType)
let delimiters = extractDelimiter (input, delimiterType)
(numbers, delimiters)
```

And all our tests pass!

There is only one more requirement left. It's passing multiple separators of any length at once. Translate this into a test:

```
[<Theory>]
[<InlineData("//[*][%]\n1*2%3", 6)>]
[<InlineData("//[!!][..]\n1!!2..3", 6)>]
let ``Multiple delimiters can be passed at once`` (input, expected) =
let result = Add input
Assert.Equal(Ok expected, result)
```

Similar to the previous step, we have to change extracting numbers and delimiters functions. Luckily, we don't have to change a lot of code. Working code looks in extracting delimiter looks like so:

```
| MoreThanOneCharacterLong ->
let delimitersStart = numbers.IndexOf "["
let delimitersEnd = numbers.IndexOf "\n" - 1
let delimiters = numbers.[delimitersStart..delimitersEnd]
let customDelimiters =
delimiters.Split([| "["; "]" |],
StringSplitOptions.RemoveEmptyEntries)
Array.concat [| defaultDelimiters
customDelimiters |]
```

and extracting numbers:

```
MoreThanOneCharacterLong ->
let delimiterEnd = numbers.LastIndexOf "]" + 2
numbers.[delimiterEnd..numbers.Length]
```

And that's all! String calculator kata in F# is done! Full code is on my github.

I have to say I've enjoyed it a lot. There were times when I was stuck even though this kata looks relatively simple, right? F# also seems like an interesting language. Not only because of a different paradigm but also for being succinct. I've also loved modeling with types. For a C# developer, it's just so easy.

The best part? It only made me more hungry! Expect more F# code from me. If you have any ideas about the next steps send me a tweet.