获取两个流并在 OCaml 中组合它们
Taking two streams and combining them in OCaml
我想以递增的顺序获取两个整数流,并将它们组合成一个不包含重复项且应按递增顺序排列的流。我按以下方式定义了流的功能:
type 'a susp = Susp of (unit -> 'a)
let force (Susp f) = f()
type 'a str = {hd : 'a ; tl : ('a str) susp }
let merge s1 s2 = (* must implement *)
第一个函数通过将计算包装在函数中来暂停计算,第二个函数计算函数并向我提供计算结果。
我想模仿你如何组合列表的逻辑,即匹配两个列表并检查哪些元素更大、更小或相等,然后追加(cons)整数以使结果列表排序.
但是,我知道我当然不能只用流来做这件事,因为我不能像列表一样遍历它,所以我想我需要逐个整数进行比较,然后暂停计算并继续这样做构建结果流。
然而,我对如何实现这样的逻辑有点不知所措,假设我应该这样做,所以如果有人能指出我正确的方向,那就太好了。
谢谢!
如果输入的序列是有序的,合并列表和序列之间没有太大区别。考虑以下列表合并函数:
let rec merge s t =
match s, t with
| x :: s , [] | [], x :: s -> x :: s
| [], [] -> s
| x :: s', y :: t' ->
if x < y then
x :: (merge s' t)
else if x = y then
x :: (merge s' t')
else
y :: (merge s t')
此函数仅使用列表的两个属性:
- 能够将潜在的第一个元素与列表的其余部分分开
- 将元素添加到列表前面的能力
这表明我们可以将此函数重写为签名上的仿函数
module type seq = sig
type 'a t
(* if the seq is non-empty we split the seq into head and tail *)
val next: 'a t -> ('a * 'a t) option
(* add back to the front *)
val cons: 'a -> 'a t -> 'a t
end
那么如果我们把list上的模式匹配换成调用next
,cons操作换成调用cons
,前面的函数就变成了:
module Merge(Any_seq: seq ) = struct
open Any_seq
let rec merge s t =
match next s, next t with
| Some(x,s), None | None, Some (x,s) ->
cons x s
| None, None -> s
| Some (x,s'), Some (y,t') ->
if x < y then
cons x (merge s' t)
else if x = y then
cons x (merge s' t')
else
cons y (merge s t')
end
然后,对于列表,我们的实现是:
module List_core = struct
type 'a t = 'a list
let cons = List.cons
let next = function
| [] -> None
| a :: q -> Some(a,q)
end
module List_implem = Merge(List_core)
可以用
测试
let test = List_implem.merge [1;5;6] [2;4;9]
为您的流类型实现相同的功能只是为流编写一个类似的 Stream_core
模块的问题。
我想以递增的顺序获取两个整数流,并将它们组合成一个不包含重复项且应按递增顺序排列的流。我按以下方式定义了流的功能:
type 'a susp = Susp of (unit -> 'a)
let force (Susp f) = f()
type 'a str = {hd : 'a ; tl : ('a str) susp }
let merge s1 s2 = (* must implement *)
第一个函数通过将计算包装在函数中来暂停计算,第二个函数计算函数并向我提供计算结果。
我想模仿你如何组合列表的逻辑,即匹配两个列表并检查哪些元素更大、更小或相等,然后追加(cons)整数以使结果列表排序.
但是,我知道我当然不能只用流来做这件事,因为我不能像列表一样遍历它,所以我想我需要逐个整数进行比较,然后暂停计算并继续这样做构建结果流。
然而,我对如何实现这样的逻辑有点不知所措,假设我应该这样做,所以如果有人能指出我正确的方向,那就太好了。
谢谢!
如果输入的序列是有序的,合并列表和序列之间没有太大区别。考虑以下列表合并函数:
let rec merge s t =
match s, t with
| x :: s , [] | [], x :: s -> x :: s
| [], [] -> s
| x :: s', y :: t' ->
if x < y then
x :: (merge s' t)
else if x = y then
x :: (merge s' t')
else
y :: (merge s t')
此函数仅使用列表的两个属性:
- 能够将潜在的第一个元素与列表的其余部分分开
- 将元素添加到列表前面的能力
这表明我们可以将此函数重写为签名上的仿函数
module type seq = sig
type 'a t
(* if the seq is non-empty we split the seq into head and tail *)
val next: 'a t -> ('a * 'a t) option
(* add back to the front *)
val cons: 'a -> 'a t -> 'a t
end
那么如果我们把list上的模式匹配换成调用next
,cons操作换成调用cons
,前面的函数就变成了:
module Merge(Any_seq: seq ) = struct
open Any_seq
let rec merge s t =
match next s, next t with
| Some(x,s), None | None, Some (x,s) ->
cons x s
| None, None -> s
| Some (x,s'), Some (y,t') ->
if x < y then
cons x (merge s' t)
else if x = y then
cons x (merge s' t')
else
cons y (merge s t')
end
然后,对于列表,我们的实现是:
module List_core = struct
type 'a t = 'a list
let cons = List.cons
let next = function
| [] -> None
| a :: q -> Some(a,q)
end
module List_implem = Merge(List_core)
可以用
测试let test = List_implem.merge [1;5;6] [2;4;9]
为您的流类型实现相同的功能只是为流编写一个类似的 Stream_core
模块的问题。