我希望能够更熟悉函数式编程,而我自己设定的第一个教育任务是将计算音频频率的程序从C#转换为F#。原始应用程序的内容是一个很大的"用于"选择大数组中值的子集的循环;采用哪些值取决于最后接受的值以及从那时起所看到的值的排序列表。在迭代之间存在一些变量,以跟踪确定下一个值的进度。
我第一次尝试使这个循环更多"功能性"涉及一个尾递归函数,其参数包括数组,到目前为止的结果集,最近看到的值的排序列表,以及需要在执行之间保持的一些其他项。这看起来很笨拙,我觉得通过把以前变成的变量变成这个递归函数的参数,我已经获得了任何东西。
函数式编程大师如何处理这种任务?这是一个特殊的情况,其中一个纯粹的"功能性方法并不合适,因为我觉得它们会降低“纯度”,所以我错误地避免使用可变变量。我的功能?也许他们不会让它变得不那么纯粹,因为它们只存在于该功能的范围内。我还没有感觉到这一点。
这是一个尝试升级代码,其中一些" let"语句和状态的实际组件被删除(" temp"是需要处理的中间结果数组):
let fif (_,_,_,_,fif) = fif
temp
|> Array.fold (fun (a, b, c, tentativeNextVals, acc) curVal ->
if (hasProperty curVal c) then
// do not consider current value
(a, b, c, Seq.empty, acc)
else
if (hasOtherProperty curVal b) then
// add current value to tentative list
(a, b, c, tentativeNextVals.Concat [curVal], acc)
else
// accept a new value
let newAcceptedVal = chooseNextVal (tentativeNextVals.Concat [curVal])
(newC, newB, newC, Seq.empty, acc.Concat [newAcceptedVal])
) (0,0,0,Seq.empty,Seq.empty)
|> fif
答案 0 :(得分:2)
使用折叠这样的东西?
let filter list =
List.fold (fun statevar element -> if condition statevar then statevar else element) initialvalue list
答案 1 :(得分:0)
尝试使用Seq.skip和Seq.take:
let subset (min, max) seq =
seq
|> Seq.skip (min)
|> Seq.take (max - min)
此函数将接受数组但返回一个序列,因此您可以使用Array.ofSeq将其转换回来。
PS:如果您的目标是让您的计划保持正常运作,那么最重要的规则是:尽可能避免可变性。这意味着您可能不应该使用数组;使用不可变的列表。如果您正在使用阵列进行快速随机访问,请选择它;只是一定要永远不要设置索引。