OCaml - 返回包含该列表尾部的列表

时间:2011-04-13 16:03:06

标签: ocaml

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

我正在尝试使用List库,但我不确定如何使用。到目前为止,我知道我必须使用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
编辑:很抱歉,我为返回的函数指定的内容不正确。只需使用正确的输出更新它。

4 个答案:

答案 0 :(得分:4)

正如我在评论中所说,这些不是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]; []]

答案 1 :(得分:4)

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

您在问题中给出的答案很好但是不注释类型并使用function会更加惯用:

let rec tails = function
  | [] -> [[]]
  | _::xs' as xs -> xs::tails xs'

其他语言(如F#)提供了List.unfold函数,tails可以用来编写。{/ p>

答案 2 :(得分:3)

啊,在原始列表上积累的旧技巧将tails转换为catamorphism。只使用List模块上的函数

,无需显式递归即可完成此操作
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]; []]

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

答案 3 :(得分:1)

“不使用递归”......为什么?即使在List库之外,递归也是一种有用的工具。

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

并使用List.fold_left表达它,如果你想避免递归,但这是复杂的,所以你应该更喜欢我认为的直接版本:

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

最后,使用延续版本可以摧毁你的大脑,但我不记得确切的代码。粗略地说,延续等同于直接版本的“累加器”。