2011-04-13 45 views
3

的尾巴名單對於[1;2;3;4;5],我想回到[[1;2;3;4;5];[2;3;4;5];[3;4;5;];[4;5];[5];[]]OCaml的 - 返回一個包含該列表

我試圖使用列表庫,但我不能確定如何。到目前爲止,我知道我必須使用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 

編輯:對不起,我指定的函數返回的是不正確的。剛剛更新了正確的輸出。

+0

在模塊'List'中沒有函數會將列表'l'的尾部呈現給您傳遞它的函數,因此您不能擁有「l'的尾部」。如果您接受構建它們的新版本,例如使用'List.fold_right',您可以在結構上與'l'的尾部相當的列表。 – 2011-04-13 16:22:58

+1

請注意,根據您的問題,您構成問題的示例解決方案不正確,例如, '[1..4]'不是'[1..5]'的尾部。你確定你不是指[2..5]等嗎? – 2011-04-13 17:24:58

+0

@Pascal:沒有必要放棄共享尾巴:只需將原始列表作爲「fold」的一部分。 – 2011-04-19 15:06:23

回答

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]; []] 
+0

謝謝。你能向我解釋一下這個功能在做什麼嗎? acc如何工作等。 – jlaguatan 2011-04-13 23:19:56

+1

'fold_right'將累加器應用於列表中元素從右到左的函數。每個調用都會創建一個新的「尾部」,並且下一個「尾部」是帶有當前元素('e')的前一個(「List.hd acc」)。從[]追加4,從[4]追加3,從[3; 4]追加2,... – nlucaroni 2011-04-14 01:19:20

4

有編寫功能的內置功能方面沒有什麼好辦法。

你在你的問題給出的答案是好的,但它會更地道不註釋類型和使用function

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

其他語言,如F#,提供一個List.unfold功能tails可以寫成就......而言。

+0

完全可以根據內置函數編寫「tails」。 – 2011-04-19 15:04:21

+0

@Matías:怎麼樣? 。 – 2011-04-25 17:47:02

+0

看到我對這個問題的回答。 – 2011-04-26 00:49:32

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 

最後,使用continuations可以破壞你的大腦,但我不記得確切的代碼。粗略地說,延續相當於直接版本的「累加器」。

3

啊,原來的詭計就是在原始列表上堆積鑄造tails作爲變形。這是在不使用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]; []] 

和尾部是輸入列表實際結構尾巴,這樣List.tl l == List.hd (List.tl (tails l))

+0

+1對於我的主張是一個有效的反例,即使它很難看! – 2011-04-27 09:07:31

+0

適當的尾巴可以更簡潔地表示爲'let tails l = snd(List.fold_right(fun _(t,ts) - > List.tl t,ts @ [t])l(l,[]))'though 。這個公式是[Gibbons's](http://www.comlab.ox.ac.uk/publications/publication2330-abstract.html)。 – 2011-04-27 23:49:27

相關問題