Algorithm 家庭作业。是否可以使用嵌套模式匹配而不是辅助函数来定义函数?

Algorithm 家庭作业。是否可以使用嵌套模式匹配而不是辅助函数来定义函数?,algorithm,functional-programming,ocaml,Algorithm,Functional Programming,Ocaml,我正在用ocaml解决哈佛CS51编程课程的编程辅助问题。 问题是定义一个函数,该函数可以将字符列表压缩为对列表,其中每一对都包含列表中字符和字符本身的大量后续出现,也就是说,将此函数应用于列表['a';'a';'a';'a';'b';'b';'b';'b';'c';'d';'d';'d']之后,我们应该得到[(5,'a';(3,'b');(1,'c');(4,'d')]。 我提出了使用辅助函数go来解决这个问题的函数: let to_run_length (lst : char list) :

我正在用ocaml解决哈佛CS51编程课程的编程辅助问题。 问题是定义一个函数,该函数可以将字符列表压缩为对列表,其中每一对都包含列表中字符和字符本身的大量后续出现,也就是说,将此函数应用于列表['a';'a';'a';'a';'b';'b';'b';'b';'c';'d';'d';'d']之后,我们应该得到[(5,'a';(3,'b');(1,'c');(4,'d')]。 我提出了使用辅助函数go来解决这个问题的函数:

let to_run_length (lst : char list) : (int*char) list =
  let rec go i s lst1 =
    match lst1 with
      | [] -> [(i,s)]
      | (x::xs) when s <> x ->  (i,s) :: go 0 x lst1
      | (x::xs) -> go (i + 1) s xs
        in match lst with
          | x :: xs -> go 0 x lst
          | [] -> []
let to_run_length(lst:char list):(int*char)list=
让rec走,我是lst1=
将lst1与
|[]->[(一、二)]
|(x::xs)当sx->(i,s)::go 0 x lst1
|(x::xs)->go(i+1)s xs
与lst匹配
|x::xs->go 0 x lst
| [] -> []

我的问题是:是否可以通过嵌套模式匹配来定义递归函数to_run_length,而不定义辅助函数go。在这种情况下,我们如何存储已传递元素的计数器状态?

实现
to_run_length
的方法正确、可读且高效。这是一个很好的解决方案。(只是吹毛求疵:在中
之后的缩进是错误的)

如果要避免使用中间函数,则必须使用递归调用返回中的信息。这可以用稍微抽象一点的方式描述:

  • 空列表的运行长度编码是空列表
  • 列表
    x::xs
    的运行长度编码为,
    • 如果
      xs
      的运行长度编码以
      x
      开头,则
    • 如果没有,则
      (x,1):
      运行长度编码
      xs
(我故意不提供源代码,让您了解细节,但遗憾的是,使用这些相对简单的函数没有多少可隐藏的内容。)

值得思考的是:在考虑尾部递归和非尾部递归函数时,通常会遇到这种技术(我所做的类似于将尾部rec函数转换为非尾部rec形式)。在这种特殊情况下,您的原始函数不是尾部递归的。当参数/结果流只“向下”递归调用时(您返回它们,而不是重用它们以生成更大的结果),函数是尾部递归的。在我的函数中,参数/结果流只“向上”递归调用(调用具有尽可能少的信息,所有代码逻辑都是通过检查结果来完成的)。在您的实现中,流同时“向下”(整数计数器)和“向上”(编码结果)

编辑:根据原始海报的要求,以下是我的解决方案:

let rec run_length = function
  | [] -> []
  | x::xs ->
    match run_length xs with
      | (n,y)::ys when x = y -> (n+1,x)::ys
      | res -> (1,x)::res

我认为写这个函数不是一个好主意。目前的解决方案还可以

但是如果你仍然想这样做,你可以使用两种方法中的一种

1) 无需更改函数的参数。您可以定义一些顶级可变值,这些值将包含辅助函数中使用的累加器

2) 您可以向函数中添加参数来存储一些数据。在搜索延续传递样式时,您可以找到一些示例

快乐的黑客


另外,我仍然想强调,您当前的解决方案还可以,您不需要改进!

感谢您的输入。您的回答给了我一个思考材料,在不更改函数初始签名的情况下,我无法存储任何必要的信息。因此,我可能有一个选择(正如Kakadu在回答中提到的)无需更改函数的初始签名,也无需辅助函数,即可创建全局可变变量,该变量可以像计数器一样使用。这不是我所寻求的解决方案类型。不过,我已经实现了此函数的完全尾部递归版本,我想我现在已经完成了。谢谢。@user1767869:my intu假设是您不需要更改函数的签名,因为您想要的信息已经存在于返回值中。但还没有尝试过。@user1767869:我刚刚尝试过,并在不更改接口的情况下获得了5行代码。如果您愿意,我可以给您我的代码,并且认为这不违反home的指导原则工作问题(我不知道)。您可能是对的。但您仍然可以返回信息,但不能将其传递给函数。如果输入中存在对最大后续字符数的约束,则可以创建问题的解决方案。可能有一个解决方案通过生成显式模式矩阵的代码生成来满足我的约束在任意输入中,将代码最大化为后续元素,否则我还不能想出一个解决方案。好吧,这肯定不违反任何指导原则,因为这是自我教育,我只是在互联网上找到了一个合理的课程和作业,并试图尽可能多地从中学习。我想看看解决方案。