【问题标题】:Return item at position x in a list返回列表中位置 x 处的项目
【发布时间】:2011-04-16 21:09:07
【问题描述】:

我正在阅读这篇While or Tail Recursion in F#, what to use when? 的帖子,有几个人说做事的“功能方式”是使用映射/折叠和高阶函数,而不是递归和循环。

我有这个函数可以返回列表中 x 位置的项目:

let rec getPos l c =  if c = 0 then List.head l else getPos (List.tail l) (c - 1)

如何将其转换为更具功能性?

【问题讨论】:

    标签: f# tail-recursion


    【解决方案1】:

    这是一个原始列表函数(也称为List.nth)。

    可以使用递归,尤其是在创建基本构建块时。虽然使用模式匹配而不是if-else 会更好,像这样:

    let rec getPos l c =
       match l with
       | h::_ when c = 0 -> h
       | _::t -> getPos t (c-1)
       | [] -> failwith "list too short"
    

    可以用List.fold表达这个函数,但是结果不如递归版本清晰。

    【讨论】:

    • 很好,但我更愿意做 ´| h::[] -> h´ 表示第一个匹配条件
    【解决方案2】:

    我不确定你所说的更多功能是什么意思。

    你自己滚动这个作为学习练习吗?

    如果没有,你可以试试这个:

    > let mylist = [1;2;3;4];;
    > let n = 2;;
    > mylist.[n];;
    

    【讨论】:

      【解决方案3】:

      您的定义已经很实用了,因为它使用尾递归函数而不是命令式循环构造。但是,它看起来也像是 Scheme 程序员可能写的东西,因为您使用的是 headtail

      我怀疑您真的在问如何以更惯用的 ML 风格编写它。答案是使用模式匹配:

      let rec getPos list n =
          match list with
          | hd::tl ->
              if n = 0 then hd
              else getPos tl (n - 1)
          | [] -> failWith "Index out of range."
      

      现在在代码中显示了对列表结构的递归。如果模式匹配不是详尽的,您也会收到警告,因此您不得不处理索引太大的错误。

      你说得对,函数式编程也鼓励使用 map 或 fold 之类的组合器(所谓的无点样式)。但是太多只会导致代码不可读。在这种情况下,我认为没有必要这样做。

      当然,Benjol 是对的,实际上你只需写 mylist.[n]

      【讨论】:

        【解决方案4】:

        如果你想为此使用高阶函数,你可以这样做:

        let nth n = Seq.take (n+1) >> Seq.fold (fun _ x -> Some x) None
        
        let nth n = Seq.take (n+1) >> Seq.reduce (fun _ x -> x)
        

        但这个想法实际上是拥有基本结构并将它们组合起来构建您想要的任何东西。获取序列的第 n 个元素显然是您应该使用的基本块。如果您想要第 n 项,正如 Benjol 提到的,请执行 myList.[n]

        对于构建基本结构,使用递归或可变循环并没有错(通常,您必须这样做)。

        【讨论】:

          【解决方案5】:

          不是作为一个实际的解决方案,而是作为一个练习,这里是通过foldr 表达nth 的方法之一,或者用F# 术语,List.foldBack

          let myNth n xs =
              let step e f = function |0 -> e |n -> f (n-1)
              let error _ = failwith "List is too short"
              List.foldBack step xs error n
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-09-19
            • 1970-01-01
            • 2017-12-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-24
            相关资源
            最近更新 更多