OCaml - 列表列表递归 'if expression'
OCaml - list of lists recursive 'if expression'
我想创建一个 rec 函数,比如 oddleninLdbl
,它以一个列表列表作为参数 "L" 和 returns 的一个副本"L",其中奇数长度的列表已“加倍”- 加倍意味着列表将与自身连接。
为了说明以上内容,想法是这样的:
oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]];;
return如下:
[[]; [5;5]; [23;5]; [45;65;2;45;65;2]; []; [34;85;7;22;1;34;85;7;22;1]]
它也应该适用于任何列表类型,例如这里的字符串:
oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]]
应该return:
[[]; ["mi";"lo"]; ["la";"la"]; ["lo";"co";"mo";"lo";"co";"mo"]]
我一直 运行 围绕着这个问题转了一圈。如果我没记错的话,我知道我的 'if expression' 应该围绕与列表中列表长度相关的东西,当它是 List.length mod 2 = 1
时,子列表应该与自身连接。
但是,我无法应用它,因为我从未使用过列表列表!这个函数应该怎么写?非常感谢您的帮助。
编辑 1:
我已尝试执行以下操作
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
但我得到的答案是:
# oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]] ;;
- : int list list =
[[5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]; [5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]]
# oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]] ;;
- : string list list =
[["mi"; "lo"]; ["la"]; ["lo"; "co"; "mo"]; ["mi"; "lo"]; ["la"];["lo"; "co"; "mo"]]
# oddleninLdbl [5;6;3;4;6] ;;
- : int list = [5; 6; 3; 4; 6; 5; 6; 3; 4; 6]
# oddleninLdbl [4;5] ;;
- : int list = [5; 5]
# oddleninLdbl [4;5;8] ;;
- : int list = [4; 5; 8; 4; 5; 8]
# oddleninLdbl [4;5;8;9] ;;
- : int list = [5; 8; 9; 5; 8; 9]
# oddleninLdbl ["mi";"lo"] ;;
- : string list = ["lo"; "lo"]
# oddleninLdbl ["mi";"lo";"co"] ;;
- : string list = ["mi"; "lo"; "co"; "mi"; "lo"; "co"]
# oddleninLdbl ["mi"] ;;
- : string list = ["mi"; "mi"]
显然不是该函数的预期功能。我的代码中的罪魁祸首在哪里?有人可以给我他们的诊断吗?
编辑 2:
let double_list l = (List.hd l)@(List.hd l);;
let p l = (List.length (List.hd l)) mod 2 = 1 ;;
let apply p double_list l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then double_list hd else hd in
aux (hd :: acc) tl ;;
我在这方面遇到了语法错误,我肯定在这里跳过了一些东西。你怎么看?
在处理您不容易理解的结构时,一个好的经验法则是分而治之。
你的问题,在这里,可以分解成多个部分:
- 获取列表的列表和return列表的列表
- 当列表为奇数时,将其加倍
因此,您应该首先创建一个将列表加倍的简单函数
let double_list l = (* double the elements in a list of elements *)
那么你应该创建一个函数,它遍历一个元素列表,并在当前元素对应于一个谓词时做一些事情p
let apply p f l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then f hd else hd in
aux (hd :: acc) tl
in aux [] l
现在您唯一需要的就是正确的谓词 p
并且您已经实现了函数 f
,它应该可以完美运行。
总而言之,当您可以通过将问题分解为更小的问题来简化问题时,永远不要害怕表面上的复杂性。
编辑:
这是您的代码:
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
这不是惯用的 OCaml,请尝试改用模式匹配:
let double_list l = l@l;;
let rec oddleninLdbl l =
match l with
| [] -> []
| hd :: tl ->
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl tl;;
如您所见,您正在检查 l
是否为奇数,而不是其元素,这不是您想要做的。您想要检查 hd
是否为奇数并将其加倍,然后继续遍历列表的其余部分并将 hd
(加倍或不加倍)附加到递归调用的结果。在这里,当 l
是奇数时,你将它加倍并停止,如果它不是你只是忘记列表的头部并将其余部分加倍(因为其余部分在逻辑上将是一个奇数列表)。
我想创建一个 rec 函数,比如 oddleninLdbl
,它以一个列表列表作为参数 "L" 和 returns 的一个副本"L",其中奇数长度的列表已“加倍”- 加倍意味着列表将与自身连接。
为了说明以上内容,想法是这样的:
oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]];;
return如下:
[[]; [5;5]; [23;5]; [45;65;2;45;65;2]; []; [34;85;7;22;1;34;85;7;22;1]]
它也应该适用于任何列表类型,例如这里的字符串:
oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]]
应该return:
[[]; ["mi";"lo"]; ["la";"la"]; ["lo";"co";"mo";"lo";"co";"mo"]]
我一直 运行 围绕着这个问题转了一圈。如果我没记错的话,我知道我的 'if expression' 应该围绕与列表中列表长度相关的东西,当它是 List.length mod 2 = 1
时,子列表应该与自身连接。
但是,我无法应用它,因为我从未使用过列表列表!这个函数应该怎么写?非常感谢您的帮助。
编辑 1:
我已尝试执行以下操作
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
但我得到的答案是:
# oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]] ;;
- : int list list =
[[5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]; [5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]]
# oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]] ;;
- : string list list =
[["mi"; "lo"]; ["la"]; ["lo"; "co"; "mo"]; ["mi"; "lo"]; ["la"];["lo"; "co"; "mo"]]
# oddleninLdbl [5;6;3;4;6] ;;
- : int list = [5; 6; 3; 4; 6; 5; 6; 3; 4; 6]
# oddleninLdbl [4;5] ;;
- : int list = [5; 5]
# oddleninLdbl [4;5;8] ;;
- : int list = [4; 5; 8; 4; 5; 8]
# oddleninLdbl [4;5;8;9] ;;
- : int list = [5; 8; 9; 5; 8; 9]
# oddleninLdbl ["mi";"lo"] ;;
- : string list = ["lo"; "lo"]
# oddleninLdbl ["mi";"lo";"co"] ;;
- : string list = ["mi"; "lo"; "co"; "mi"; "lo"; "co"]
# oddleninLdbl ["mi"] ;;
- : string list = ["mi"; "mi"]
显然不是该函数的预期功能。我的代码中的罪魁祸首在哪里?有人可以给我他们的诊断吗?
编辑 2:
let double_list l = (List.hd l)@(List.hd l);;
let p l = (List.length (List.hd l)) mod 2 = 1 ;;
let apply p double_list l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then double_list hd else hd in
aux (hd :: acc) tl ;;
我在这方面遇到了语法错误,我肯定在这里跳过了一些东西。你怎么看?
在处理您不容易理解的结构时,一个好的经验法则是分而治之。
你的问题,在这里,可以分解成多个部分:
- 获取列表的列表和return列表的列表
- 当列表为奇数时,将其加倍
因此,您应该首先创建一个将列表加倍的简单函数
let double_list l = (* double the elements in a list of elements *)
那么你应该创建一个函数,它遍历一个元素列表,并在当前元素对应于一个谓词时做一些事情p
let apply p f l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then f hd else hd in
aux (hd :: acc) tl
in aux [] l
现在您唯一需要的就是正确的谓词 p
并且您已经实现了函数 f
,它应该可以完美运行。
总而言之,当您可以通过将问题分解为更小的问题来简化问题时,永远不要害怕表面上的复杂性。
编辑:
这是您的代码:
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
这不是惯用的 OCaml,请尝试改用模式匹配:
let double_list l = l@l;;
let rec oddleninLdbl l =
match l with
| [] -> []
| hd :: tl ->
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl tl;;
如您所见,您正在检查 l
是否为奇数,而不是其元素,这不是您想要做的。您想要检查 hd
是否为奇数并将其加倍,然后继续遍历列表的其余部分并将 hd
(加倍或不加倍)附加到递归调用的结果。在这里,当 l
是奇数时,你将它加倍并停止,如果它不是你只是忘记列表的头部并将其余部分加倍(因为其余部分在逻辑上将是一个奇数列表)。