I am experienced in C# but new to F# and Functional Programming. Now I am trying to implement a class library in F#. Here is one of the functions: It takes a list of integers <=9 and change consecutive 9 like 9,9,9,9 to 9, 10, 11, 12. For example [9;9;9;1;4;0;1;9;9;9;9] will be changed to [9; 10; 11; 1; 4; 0; 1; 9; 10; 11; 12].
C# function is trivial:
void ReleaseCap(List<int> items)
{
for (int i = 1; i < items.Count; i++)
{
var current = items[i];
var previous = items[i - 1];
//If curernt value = 9 and previous >=9, then current value should be previous+1
if (current == 9 && previous >= 9)
{
items[i] = previous + 1;
}
}
}
Now is my F# tail recursive one. Instead of loop the List by index, it recursively move item from an initial list to an processed list until everything in the initial list is gone:
let releaseCap items =
let rec loop processed remaining = //tail recursion
match remaining with
| [] -> processed //if nothing left, the job is done.
| current :: rest when current = 9 -> //if current item =9
match processed with
// previous value >= 9, then append previous+1 to the processed list
| previous :: _ when previous >= 9 -> loop (previous+1 :: processed) rest
//if previous < 9, the current one should be just 9
| _ -> loop (current :: processed) rest
//otherwise, just put the current value to the processed list
| current :: rest -> loop (current :: processed) rest
loop [] items |> List.rev
While the C# version is trivial and intuitive, the F# code is verbose and not as intuitive. Is there any part of the F# code can be improved to make it more elegant?
You can reuse existing functions in order to simplify your code.
Normally when you change items in a list you think of a map
but in this case you have something to remember from your previous computation which should be passed for each item, so you should aim to fold
related functions.
Here's one: List.scan
let releaseCap items =
items
|> List.scan (fun previous current ->
if current = 9 && previous >= 9 then previous + 1
else current) 0
|> List.tail
FP is not just about using recursion instead of loops. Recursion is typically used in basic and reusable functions, then by combining those functions you can solve complex problems.
NOTE: You are comparing your C# solution with your F# solution, but did you notice that apart from the language there is an important difference between both solutions? Your C# solution uses mutability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With