SML - 双向无限和有限序列交织

时间:2017-01-15 11:44:22

标签: sequence sml smlnj sequences seq

我有下一个数据类型和函数声明:

datatype direction = Back | Forward
datatype 'a bseq = bNil | bCons of 'a * (direction -> 'a bseq)

fun bHead (bCons (x, _)) = x
  | bHead bNil = raise EmptySeq

fun bForward(bCons(_, xf)) = xf Forward
  | bForward bNil = raise EmptySeq

fun bBack (bCons (_, xf)) = xf Back
  | bBack bNil = raise EmptySeq

fun intbseq k =
  let fun go Forward = intbseq (k+1)
        | go Back = intbseq (k-1)
  in bCons (k, go) end

下一个函数由我编写,用于交错两个序列: 如果第一个seq是... ,1,2,3,4,5, .....而第二个是...,5,6,7,8,9,... 他们交错的新序列是:

... ,3,-1,4,0,5,1,6,2,7,3, ......

代码:

fun binterleaving_aux _ bNil yq = yq
  | binterleaving_aux _ xq bNil = xq
  | binterleaving_aux firstb (bCons(x,xf)) (bCons(y,yf)) =
    bCons(x, fn dir => 
      if dir = Forward 
      then binterleaving_aux true (bCons (y, yf)) (xf dir)
      else if firstb 
           then binterleaving_aux false (yf dir) (xf dir)
           else binterleaving_aux false (bCons (y,yf)) (xf dir)));

fun binterleaving bseq1 bseq2 = binterleaving_aux true bseq1 bseq2;

对于那个例子:

binterleaving (intbseq 5) (intbseq 1);
bForward(it);
bForward(it);
bForward(it);
bForward(it);
bBack(it);
bBack(it);
bBack(it);
bBack(it);

它适用于2个无限序列。

问题是至少其中一个是有限的。

例如,如果我这样做:

binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 5);
bForward(it);
bForward(it);
bForward(it);
bForward(it);
bBack(it);
bBack(it);
bBack(it);
bBack(it);

如果我回去,我会失去10和9,而如果我先回去,则相反,当我向前迈进时,我失去了他们。

结果是按照呼叫的顺序:

val it = bCons (10,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (7,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (4,fn) : int bseq
val it = bCons (3,fn) : int bseq

正确的结果应该是:

val it = bCons (10,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (7,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (10,fn) : int bseq

我应该做的代码有哪些变化,这将是函数的行为?

1 个答案:

答案 0 :(得分:1)

  

问题是至少其中一个是有限的。

binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 0)

当你的有限序列减少到bNil时,它应该如何回到原始值?将有限序列与无限序列交织的语义似乎有点不明确。

也就是说,当有限的一个结束并且无限的一个继续时,沿着无限序列存储的参考在哪里,有限的那个以相反的方式再次开始?

采取上面的例子并评估它几步(原谅我的懒惰记法):

  binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 0)
⇒ binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil))))
                (bCons( 0, fn dir => ...intbseq (+/- 1)...))
⇒ binterleaving_aux true (bCons(10, fn dir => bCons((9, fn dir => bNil))))
                         (bCons( 0, fn dir => ...intbseq (+/- 1)...))
⇒ bCons (9, fn dir =>
      if dir = Forward
      then binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...))
                                  ((fn dir => bNil) dir)
      else ...)

通过将Forward应用于最外层的fn来评估一次,可以得到:

  bCons (9, (fn dir => ...) Forward)
⇒ bCons (9, binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...))
                                   ((fn dir => bNil) dir))
⇒ bCons (9, binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...)) bNil)
⇒ bCons (9, bCons (0, fn dir => ...intbseq (+/- 1)...))

此时,在任何能够后退的函数中都没有有限序列9的踪迹。仅在binterleaving的初始返回值。

修复主要在于binterleaving的基本情况,它抛弃了有限序列。相反,将空序列与非空序列交错的结果应该是非空序列,当反转时,返回空序列之前它为空(这可能也是空的) ,但可能是非空的。)

您可以在列表中将双向序列视为惰性zipper。 “了解你是一个Haskell”这本书的chapter on tree zippers可能值得一读。在本章的术语中,您可能需要一个返回" breadcrumb trail"的函数。列表拉链在概念上有点简单,但是散布着' bseq 的懒惰,在语法上并非如此。