接受两个流并将其合并到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 *)

一个函数通过将函数包装在函数中来暂停计算,第二个函数函数求值并向我提供计算结果。

我想模拟如何组合列表的逻辑,即在两个列表上都匹配,并检查哪些元素更大,或更小或相等,然后附加(约束)整数以对结果列表进行排序。 / p>

但是,我知道我当然不能只使用流来完成此操作,因为我无法像列表一样遍历它,所以我认为我需要逐整数进行比较,比较,然后暂停计算并继续这样做以构建产生的流。

但是,我不知如何实现这样的逻辑,假设这是我应该做的事情,因此,如果有人可以向我指出正确的方向,那将是很好的。

谢谢!

解决方法

如果对输入序列进行了排序,则合并列表和序列之间没有太大区别。考虑列表上的以下合并功能:


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

然后,如果我们通过调用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模块。