OCaml——返回一个包含该列表尾部的列表

OCaml——返回一个包含该列表尾部的列表,ocaml,Ocaml,对于[1;2;3;4;5],我想返回[1;2;3;4;5];[2;3;4;5;];[4;5];[5];[code> 我正在尝试使用列表库,但不确定如何使用。到目前为止,我知道我必须使用List.tl来获取没有第一个元素的列表 let rec tailsoflist (l : 'a list) : 'a list list = match l with [] -> [[]] | x::xs -> l::(tails xs) 我是递归地做的,但是现在我只想使用列

对于
[1;2;3;4;5]
,我想返回
[1;2;3;4;5];[2;3;4;5;];[4;5];[5];[code>

我正在尝试使用列表库,但不确定如何使用。到目前为止,我知道我必须使用List.tl来获取没有第一个元素的列表

let rec tailsoflist (l : 'a list) : 'a list list =
  match l with
      [] -> [[]]
    | x::xs -> l::(tails xs)
我是递归地做的,但是现在我只想使用列表库而不使用递归

let tails (l : 'a list) : 'a list list

编辑:对不起,伙计们,我为函数返回指定的内容不正确。刚刚用正确的输出更新了它。

正如我在评论中所说,这些不是
l
的尾部,而是
l
尾部的副本:

# let tails l = List.fold_right (fun e acc -> (e::(List.hd acc))::acc) l [[]] ;;
val tails : 'a list -> 'a list list = <fun>
# tails [1; 2; 3; 4] ;;- : int list list = [[1; 2; 3; 4]; [2; 3; 4]; [3; 4]; [4]; []]
#让tails l=List.fold#u right(fun e acc->(e:(List.hd acc))::acc)l[[]];;
val tails:“列表->”列表=
#尾巴[1;2;3;4];;-:整数列表=[[1;2;3;4];[2;3;4];[3;4];[4];[]

根据内置函数编写该函数没有好方法

您在问题中给出的答案很好,但如果不注释类型并使用
函数
,则更为惯用:

let rec tails = function
  | [] -> [[]]
  | _::xs' as xs -> xs::tails xs'
其他语言,如F#,提供了一个
列表。展开
函数,该函数的
尾部
可以按照编写。

“而不使用递归”。。。为什么?递归是一个有用的工具,即使在
列表
库之外也是如此

let rec suffixes = function
| [] -> [[]]
| hd::tl as suff -> suff :: suffixes tl
函数(由于使用了
tails
而不是
tailsoflist
,因此无法编译)返回列表的后缀列表。由于列表结构,它比前缀更容易计算

您可以使用以下后缀来表示前缀:

let prefixes li = List.map List.rev (suffixes (List.rev li));;
您可以使用累加器执行直接版本:

let prefixes li =
  let rec pref acc = function
    | [] -> List.rev acc :: []
    | hd::tl -> List.rev acc :: pref (hd :: acc) tl
  in pref [] li
并使用
列表表示。如果您想避免递归,请向左折叠
,但这很复杂,因此我认为您应该更喜欢直接版本:

let prefixes li =
  let acc, res =
    List.fold_left
      (fun (acc, res) e -> (e :: acc), (List.rev acc :: res))
      ([], []) li in
  List.rev acc :: res

最后,使用continuations的版本有可能破坏你的大脑,但我不记得确切的代码。大致上,延续相当于直接版本的“累加器”。

啊,在原始列表上累加以将
尾部作为一个反变形投射的老把戏。这是在不使用显式递归的情况下完成的,只使用
列表上的函数
模块:

let tails l = List.rev ( [] :: snd (List.fold_right
    (fun _ (t,ts) -> List.tl t, t::ts) l (l, [])) )
它会产生您期望的尾部:

# tails [1;2;3;4;5];;
- : int list list = [[1; 2; 3; 4; 5]; [2; 3; 4; 5]; [3; 4; 5]; [4; 5]; [5]; []]

并且尾部是输入列表的实际结构尾部,因此
list.tl==list.hd(list.tl(tails l))

模块
list
中没有函数将列表的尾部呈现给传递它的函数,因此不能有“list
l
的尾部”。如果您接受构建新版本的
l
列表,您可以拥有在结构上等同于
l
尾部的列表。向右折叠
。请注意,根据您的问题,您提出的问题的示例解决方案是不正确的,例如
[1..4]
不是
[1..5]
的尾部。你确定你的意思不是
[2..5]
等吗?@Pascal:没有必要放弃分享尾部:只需将原始列表作为
折叠的一部分进行穿插即可。谢谢。你能给我解释一下这个函数在做什么吗?acc是如何工作的,等等。
fold_right
将累加器应用于列表中元素从右向左的函数。每次调用都会创建一个新的“tail”,下一个“tail”是前一个(
List.hd acc
),并附加当前元素(
e
)。从[]附加4,从[4]附加3,从[3;4]附加2,…完全有可能仅根据内置函数编写
尾部
。请参阅我对这个问题的回答。+1是我的主张的有效反例,即使它非常丑陋!正确的尾部可以更简洁地表示为
let tails l=snd(List.fold\u right(fun\ut,ts)->List.tl t,ts@[t])l(l,[])
。这个公式是正确的。