将列表从一个函数连接到 OCaml 中的另一个递归函数

Concatenating list from a function to another recursive function in 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];;
  

我收到以下错误:

Error: Unbound value pentograph

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

请帮我想办法解决这个问题!

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

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],因此我们可以用列表 concatenation.

替换列表构造
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