2017-01-15 24 views
2

У меня есть следующие заявления типа данных и функция:SML - двунаправленная бесконечная и конечная последовательность чередования

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 

Следующая функция написана мной для перемежения две последовательности так: если первый след является ... ,1,2,3,4,5, ..... и второй ...,5,6,7,8,9,... новый sequance их чередованием является:

... ,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; 

И для этого exmaple:

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

Это работает отлично подходит для 2-х бесконечных последовательностей.

Проблема заключается в том, что хотя бы один из них является конечным.

Для exmaple если я:

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

Проблема в том, когда хотя бы один из них является конечным.

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 в списках. В книге «Learn You a Haskell» есть chapter on tree zippers, который может стоить прочитать. В терминологии этой главы вам может понадобиться функция, которая возвращает «путь для панировки». Список молний концептуально немного проще, но посыпается лень 'a bseq s, синтаксически не так.