[英]OCaml function with data type tree
我們給出一個包含兩種元素的樹。 它由以下數據結構定義。
type ( 'a , 'b ) tree =
Empty
| Vertexa of 'a * ( 'a , 'b ) tree list
| Vertexb of 'b * ( 'a , 'b ) tree list
編寫一個函數split:('a,'b)tree - >'list *'b list,它將'a'類型的所有元素保存到第一個列表,將所有類型'b'的元素保存在第二個列表中。
我有一個想法,遞歸地做這個,但我有點堅持這個。 即使它根本不起作用,我也會附上我的嘗試:/
let rec one drevo_list=
match drevo_list with
| [Empty]->Empty
| Empty::tl -> one tl
| Vertexa(a,b)::tl -> Vertexa(a,b@tl)
| Vertexb(a,b)::tl -> Vertexb(a,b@tl)
此功能將列表轉換為樹。 我需要它用於遞歸,因為Vertexa或Vertexb中的第二個參數是一個列表。 這工作但但遞歸部分沒有。
let rec split drevo=
match drevo with
| Empty -> [],[]
| Vertexa(a,b)-> split (one b)
| Vertexb(a,b)-> split (one b)
這部分不起作用,我不知道如何完成它。 有沒有人知道如何完成這個?
您不需要drevo_list
函數來解決此問題。 它實際上會引導你走錯方向。
您需要使用List.map
將拆分應用於樹列表。 您將獲得('a list * 'b list) list
類型的值。 現在你需要一個幫助函數concat_pairs
,它將這個值展平為一對類型'a list * 'b list
(參見標准concat
函數)。 要實現此功能,您可以使用List.fold_left
。 其余的都是微不足道的。
注意,當然這是一個貪心的解決方案。 完成后,您可能會嘗試找到更好的解決方案,更高效,尾遞歸。
這個函數至少有兩個部分難以編寫:
返回一對列表的函數需要在每個遞歸步驟中打包和解包其返回值,例如輔助函數,匹配語句或let綁定。 一種方法是編寫一個函數,將一個元素插入一對內的列表中:
let insertA a (xs, ys) = (a::xs, ys) let insertB b (xs, ys) = (xs, b::ys)
對樹類型和嵌入列表類型遞歸的函數需要兩個遞歸模式的組合。 這可以使用一組相互遞歸的函數或使用列表的高階組合器來解決。 以下是使用前一策略的解決方案概述:
let rec split s = match s with | Empty -> ([], []) | Vertexa (a, ts) -> (* if we had just one t: insertA a (split t) *) | Vertexb (a, ts) -> (* if we had just one t: insertB b (split t) *)
因此,您需要一個函數splitMany : ('a, 'b) tree list -> ('a list, 'b list)
,可以為每個單獨的樹回調split
。
and rec splitMany ts = match ts with | [] -> ([], []) | (t:ts') -> (* merge (split t) with (splitMany ts') *)
對於高階函數方法,可以通過讓函數將自身傳遞給一組高階函數來避免顯式的相互遞歸,從而不會在高階函數的實現中糾纏它:
let rec split s = match s with | Empty -> [],[] | Vertexa (a, ts) -> insertA (concat_pairs (map split ts)) | Vertexb (a, ts) -> insertB (concat_pairs (map split ts))
其中concat_pairs
是ivg的發明。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.