首页 > 解决方案 > 将一个函数的列表连接到 OCaml 中的另一个递归函数

问题描述

所以我试图在 OCaml 中编写一个相对简单的函数,它接受一个整数 n 和一个不超过 5 的整数列表,然后在所述列表中重复所有大于 1 的整数 n 次。

我已经有一个现有的函数 repeat 重复我喂它 n 次

let rec repeat : int -> 'a -> 'a list =
 fun n a ->  
  match n with  
  | 0 -> []  
  | h -> a :: repeat (h-1) a ;;

现在这是名为 Pentograph 的函数的代码

let pentograph : int -> int list-> int list =
  fun n letter ->
    match letter with 
    |[] -> []
    |h::t -> if h>1 then List.concat[(repeat n h);pentograph n t] else List.conca[h;pentograph n t];;
  

我收到以下错误:

错误:未绑定的值五线谱

在尝试使用 :: 运算符时,我也收到一个错误,因为我无法使用它来连接 2 个列表。

请帮我找出解决这个问题的方法!

编辑:如果正确答案或更优答案使用地图,那么请回答,而不是尝试修复我的代码。

标签: ocaml

解决方案


Ocaml 中的列表是一种带有一些语法糖的变体类型,而不是典型的用户定义的变体类型。列表要么是一个空列表 ( ),要么是使用运算符添加到列表中的[]某种类型的元素。由于这是一种递归类型,因此我们使用递归来处理它们也就不足为奇了。'a::

列表也可以与@运算符连接。

你的repeat功能很好。我将省略显式类型并重新格式化它:

let rec repeat n a =
  match n with
  | 0 -> []
  | _ -> a :: repeat (n - 1) a

您已经定义了退出条件。如果我们要求函数重复某件事0,我们会得到一个空列表。否则,我们a会在重复该功能的结果的前面加上一个更少的重复。第二阶段设置状态更新,使其更接近退出条件。

repeat 4 6
6 :: repeat 3 6
6 :: 6 :: repeat 2 6
6 :: 6 :: 6 :: repeat 1 6
6 :: 6 :: 6 :: 6 :: repeat 0 6
[6; 6; 6; 6]

pentograph所以,对你的函数做同样的事情。重复需要很多时间,并且需要一个列表。我们可以递归地遍历列表,所以自然退出条件是一个空列表。如果列表为空,则结果应为空列表。

let rec pentograph n lst =
  match lst with
  | [] -> []

否则,列表将是某个值和列表的其余部分。

let rec pentograph n lst =
  match lst with
  | [] -> []
  | x::xs -> ...

现在我们知道这x是列表的第一个元素,所以我们可以检查它是否大于 1。

let rec pentograph n lst =
  match lst with
  | [] -> []
  | x::xs -> 
      if x > 1 then ...
      else ...

如果它大于 1,我们将把重复工作分包出来,并将其放在列表其余部分的repeat运行前面。pentograph如果不是,我们将只pentograph在列表的其余部分上运行该函数,而忽略x我们的结果。

let rec pentograph n lst =
  match lst with
  | [] -> []
  | x::xs -> 
      if x > 1 then 
        repeat n x :: pentograph n xs
      else 
        pentograph n xs

现在,让我们尝试对pentograph 2 [1; 2; 3].

pentograph 2 [1; 2; 3]
pentograph 2 [2; 3]
repeat 2 2 :: pentograph 2 [3]
repeat 2 2 :: repeat 2 3 :: pentograph 2 []
repeat 2 2 :: repeat 2 3 :: []
[2; 2] :: [3; 3] :: []
[[2; 2]; [3; 3]]

现在,您可能正在寻找的结果是,所以我们可以用列表连接[2; 2; 3; 3]替换列表构造。

let rec pentograph n lst =
  match lst with
  | [] -> []
  | x::xs -> 
      if x > 1 then 
        repeat n x @ pentograph n xs
      else 
        pentograph n xs

现在:

pentograph 2 [1; 2; 3]
pentograph 2 [2; 3]
repeat 2 2 @ pentograph 2 [3]
repeat 2 2 @ repeat 2 3 @ pentograph 2 []
repeat 2 2 @ repeat 2 3 @ []
[2; 2] @ [3; 3] @ []
[2; 2; 3, 3]

最后,作为一种风格偏好,我们可以在模式匹配上使用守卫,而不是 if/else 来稍微清理一下。

let rec pentograph n lst =
  match lst with
  | [] -> []
  | x::xs when x > 1 -> repeat n x @ pentograph n xs
  | _::xs -> pentograph n xs

推荐阅读