If statement OCaml-递归列表列表';if表达式';

If statement OCaml-递归列表列表';if表达式';,if-statement,recursion,ocaml,nested-lists,If Statement,Recursion,Ocaml,Nested Lists,我想创建一个rec函数,比如说oddlinenldbl,它将列表列表“L”作为参数,并返回一个“L”的副本,其中奇数长度的列表已“加倍”-加倍表示列表将与其自身连接 为了说明上述情况,我们的想法是: oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]];; 返回以下内容: [[]; [5;5]; [23;5]; [45;65;2;45;65;2]; []; [34;85;7;22;1;34;85;7;22;1]] 它还应适

我想创建一个rec函数,比如说
oddlinenldbl
,它将列表列表“L”作为参数,并返回一个“L”的副本,其中奇数长度的列表已“加倍”-加倍表示列表将与其自身连接

为了说明上述情况,我们的想法是:

oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]];;
返回以下内容:

[[]; [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"]]
应返回:

[[]; ["mi";"lo"]; ["la";"la"]; ["lo";"co";"mo";"lo";"co";"mo"]]
我一直在绕着这个绕圈子。如果我没有弄错的话,我知道我的“如果表达式”应该围绕列表中列表长度相关的内容旋转,当它是
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 ;;

我在这一个语法错误肯定我跳过了一些这里。你认为呢?

在处理你不容易理解的结构时,一个很好的经验法则是分而治之

在这里,您的问题可以分解为多个部分:

  • 获取列表并返回列表列表
  • 当列表为奇数时,将其加倍
  • 因此,您应该首先创建一个简单的函数,将列表加倍

    让double_list l=(*将元素列表中的元素加倍*)
    
    然后,您应该创建一个函数,该函数遍历元素列表,并在当前元素与谓词
    p

    让应用p f l=
    让rec aux acc l=将l与
    |[]->List.rev acc
    |hd::tl->
    设hd=如果p hd那么f hd else hd in
    辅助(hd::acc)tl
    在辅助[]l中
    
    现在,您只需要正确的谓词
    p
    ,您已经实现了函数
    f
    ,它应该可以完美地工作

    总而言之,当你可以通过把问题划分成更小的问题来简化你的问题时,千万不要害怕表面上的复杂性

    编辑:

    这是您的代码:

    let double_list l=l@l;;
    让我来记录一下=
    如果l=[]
    然后[]
    否则(
    让t=List.tl输入
    如果((列表长度l)模块2=1)
    然后是双重列表
    还有奥德列宁特吗
    ) ;;
    
    这不是惯用的OCaml,请尝试改用模式匹配:

    let double_list l=l@l;;
    让我来记录一下=
    匹配
    | [] -> [] 
    |hd::tl->
    如果((列表长度l)模块2=1)
    然后是双重列表
    else-ldbl tl;;
    

    如您所见,您正在检查
    l
    是否为奇数,而不是它的元素,这不是您想要做的。您需要检查
    hd
    是否为奇数并将其加倍,然后继续遍历列表的其余部分,并将
    hd
    (加倍或不加倍)附加到递归调用的结果中。在这里,当
    l
    是奇数时,你将其加倍并停止,如果不是,你只需忘记列表的标题并加倍其余部分(因为其余部分在逻辑上是奇数列表)。

    我遵循了你的提示@Lhooq,在上面的编辑中将我的问题分解为多个部分。作为一名自学者,我正在努力理解这门语言,并希望获得一些关于我的错误的反馈。当然,射击,我会尝试回答;-)只要你们有时间,我已经在上面编辑了我的文章,通常它会出现在编辑1部分。我编辑了我的答案;-)我做了必要的修改,它成功了!在第一个函数中,我用它的hd替换了l。然后,在我的第二个函数的第二部分,用它的头替换了l。我还让它在末尾递归地遍历列表的其余部分,就像这样,对于第一种情况,double_list l::oddlinenldbl tl,然后是第二种情况,它成功了!我非常感谢你的解释!