Rya*_*yan 4 f# functional-programming
我在C#方面很有经验,但对F#和功能编程很新.现在我想在F#中实现一个类库.这是其中一个函数:它取一个整数列表<= 9并改变连续9,如9,9,9,9到9,10,11,12.例如[9; 9; 9; 1; 4; 0; 1; 9; 9; 9; 9]将改为[9; 10; 11; 1; 4; 0; 1; 9; 10; 11; 12.
C#功能很简单:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在是我的F#尾递归.它不是通过索引循环List,而是递归地将项目从初始列表移动到已处理的列表,直到初始列表中的所有内容都消失为止:
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
Run Code Online (Sandbox Code Playgroud)
虽然C#版本是微不足道和直观的,但F#代码很冗长而且不那么直观.是否可以改进F#代码的任何部分以使其更优雅?
您可以重用现有函数以简化代码.通常,当您更改列表中的项目时,您会想到一个map但是在这种情况下,您需要记住以前计算中应该为每个项目传递的内容,因此您应该针对fold相关函数.
这是一个: List.scan
let releaseCap items =
items
|> List.scan (fun previous current ->
if current = 9 && previous >= 9 then previous + 1
else current) 0
|> List.tail
Run Code Online (Sandbox Code Playgroud)
FP不只是使用递归而不是循环.递归通常用于基本和可重用的函数,然后通过组合这些函数,您可以解决复杂的问题.
注意:您正在将C#解决方案与F#解决方案进行比较,但是您是否注意到除了语言之外,两种解决方案之间存在重要差异?您的C#解决方案使用可变性.