【问题标题】:What's the most "functional" way to select a subset from this array?从这个数组中选择一个子集的最“实用”的方法是什么?
【发布时间】:2013-11-28 09:54:52
【问题描述】:

我想更熟悉函数式编程,我为自己设定的第一个教育任务是将计算音频频率的程序从 C# 转换为 F#。原始应用程序的核心是一个大的“for”循环,它在一个大数组中选择一个值的子集;采用哪些值取决于最后接受的值和此后看到的值的排序列表。有一些变量在迭代之间持续存在,以跟踪确定下一个值的进度。

我第一次尝试使这个循环更“功能化”涉及一个尾递归函数,它的参数包括数组、到目前为止的结果集、最近看到的值的排名列表,以及需要在它们之间持续存在的一些其他项目处决。这看起来很笨拙,而且我不觉得通过将曾经是变量的所有内容都转换为这个递归函数的参数,我没有得到任何好处。

函数式编程大师将如何处理此类任务?这是一种特殊情况,其中“纯”函数方法不太适合,我是否因为我觉得它们降低了我的函数的“纯度”而回避可变变量是错误的?也许它们不会降低纯度,因为它们只存在于该函数的范围内。我还没有感觉。

这是对代码的一次尝试性提炼,删除了一些“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

【问题讨论】:

    标签: f# functional-programming c#-to-f#


    【解决方案1】:

    尝试使用 Seq.skip 和 Seq.take:

    let subset (min, max) seq =
      seq
        |> Seq.skip (min)
        |> Seq.take (max - min)
    

    此函数将接受数组但返回一个序列,因此您可以使用 Array.ofSeq 将其转换回来。

    PS:如果您的目标是保持程序正常运行,那么最重要的规则是:尽可能避免可变性。这意味着您可能不应该使用数组;使用不可变的列表。如果您使用数组进行快速随机访问,那就去吧;只要确保永远不要设置索引。

    【讨论】:

    • 这个问题不是关于从数组中取出一个块
    【解决方案2】:

    像这样使用折叠?

    let filter list = 
        List.fold (fun statevar element -> if condition statevar then statevar else element) initialvalue list
    

    【讨论】:

      猜你喜欢
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多