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
中没有函数将列表的尾部呈现给传递它的函数,因此不能有“listl
的尾部”。如果您接受构建新版本的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,[])
。这个公式是正确的。