我要制作zip功能,即将两个惰性列表压缩为一个。例如,显示为类似于常规列表的懒惰列表以提高可读性,zip [1; 3; 5; 7; 9; 11] [2; 4; 6; 8]返回[1; 2; 3; 4; 5; 6 ; 7; 8; 9; 11]。
我执行此功能:
type 'a lazyList = LNil | LCons of 'a * (unit -> 'a lazyList);;
let zip list1 list2 =
let rec zipHelper listA listB count = match (list1, list2) with
| (LCons(xA, xfA), LCons(xB, xfB)) ->
if (count mod 2 == 0)
then LCons(xA, function() -> zipHelper (xfA()) (xfB()) (count + 1))
else LCons(xB, function() -> zipHelper (xfA()) (xfB()) (count + 1))
| (LCons(x, xf), LNil) -> LCons(x, function() -> zipHelper (xf()) LNil count)
| (LNil, LCons(x, xf)) -> LCons(x, function() -> zipHelper (xf()) LNil count)
| (LNil, LNil) -> LNil
in zipHelper list1 list2 0
;;
let rec ltake = function
| (0, _) -> []
| (_, LNil) -> []
| (n, LCons(x, xf)) -> x :: ltake(n - 1, xf())
;;
let a = (LCons(1, function() -> LCons(3, function() -> LCons(5, function() -> LCons(7, function() -> LCons(9, function() -> LCons(11, function() -> LNil)))))));;
let b = (LCons(2, function() -> LCons(4, function() -> LCons(6, function() -> LCons(8, function() -> LNil)))));;
ltake (12, zip a b);;
ltake函数有助于测试,它会在常规列表中返回懒惰列表。现在我的函数zip返回了我[1; 2; 1; 2; 1; 2; 1; 2; 1; 2; 1; 2]。
答案 0 :(得分:2)
您在match
语句中犯了一个错误。
let zip list1 list2 = let rec zipHelper listA listB count = match (list1, list2) with
您不希望在list1
和list2
上进行匹配,而是在listA
和listB
上进行匹配。
您还应该调查这些电话,
then LCons(xA, function() -> zipHelper (xfA()) (xfB()) (count + 1)) else LCons(xB, function() -> zipHelper (xfA()) (xfB()) (count + 1))
您是否真的想将两个尾巴作为参数传递?
答案 1 :(得分:0)
这是正确的代码,可以正常工作:
let zip list1 list2 =
let rec zipHelper listA listB count = match (listA, listB) with
| (LCons(xA, xfA), LCons(xB, xfB)) ->
if (count mod 2 == 0)
then LCons(xA, function() -> zipHelper (xfA()) listB (count + 1))
else LCons(xB, function() -> zipHelper listA (xfB()) (count + 1))
| (LCons(x, xf), LNil) -> LCons(x, function() -> zipHelper (xf()) LNil count)
| (LNil, LCons(x, xf)) -> LCons(x, function() -> zipHelper (xf()) LNil count)
| (LNil, LNil) -> LNil
in zipHelper list1 list2 0
;;
更改:
将要添加的元素添加到列表后,我必须调用zipHelper函数,并使用list的尾部参数,从中获取头和第二个列表,而不仅仅是尾部。
就像以前的评论员一样,错过比赛中的名单命名。
答案 2 :(得分:0)
基于@Jorge Adriano的回答,我迅速构建了他们提出的版本:
let lnil = LNil
let lcons a l = LCons (a,l)
let rec zip = function
| LCons (xA, xfA) as fA ->
( function
| LCons(xB, xfB) ->
lcons xA (fun () -> lcons xB (fun () -> zip (xfA ()) (xfB ())))
| LNil -> fA
)
| LNil ->
( function
| LCons (xB, xfB) as fB -> fB
| LNil -> LNil
)
我也将ltake
分成了take和list转换(未实现tailrecursive),并添加了重复代码来测试corecursive数据结构:
let rec ltake n = function
| LNil -> LNil
| LCons(x, xf) ->
if n == 0
then LNil
else lcons x (fun () -> ltake (n - 1) (xf ()))
let rec of_list = function
| [] -> LNil
| x :: xs -> LCons (x, fun () -> of_list xs)
let rec to_list = function
| LNil -> []
| LCons (x,xs) -> x :: (to_list (get xs))
let repeat n =
let rec aux n () = LCons (n, aux n) in
aux n ()
我们可以在原始输入上对其进行测试:
utop # ltake 12 (zip a b) |> to_list ;;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 11]
并重复:
utop # ltake 12 (zip (repeat 1 ) (repeat 2)) |> to_list ;;
- : int list = [1; 2; 1; 2; 1; 2; 1; 2; 1; 2; 1; 2]