8.3 変更可能なデータ構造
問 8.6
dataDlist, rightDlist, leftDlistを定義せよ.
解答例
   fun dataDlist (ref (CELL{data,...})) = data
   fun rightDlist (ref (CELL{right,...})) = right
   fun leftDlist (ref (CELL{left,...})) = left
問 8.7
deleteDlist と fromListToDlist を定義せよ.
解答例
   fun deleteDlist dlist =
       case dlist of
         ref NIL => ()
       | ref (CELL{left=l1 as ref (CELL{right=r2,left=l2,...}),
                   right=r1 as ref (CELL{right=r3,left=l3,...}),
                   ...}) =>
           if l1 = l2 then dlist := NIL
           else (dlist := !r1; r2 := !r1; l3 := !l1)
   fun fromListToDlist L = foldl (fn (x,y) => (insertDlist x y;y)) (ref NIL) (rev L)
補足: fromListToDlistは、リストの末尾から循環リストに追加してい く関数である。 foldrは末尾再帰の実装が困難なため、
fun fromListToDlist L = foldr (fn (x,y) => (insertDlist x y;y)) (ref NIL) Lよりスタックオーバフローなどの危険も少なく効率がよい。
この観点から、リストを生成する関数、例えばtoListなども以 下のような実装が望ましい。fun toList L = let fun loop (l,A) visited = if member l visited then rev A else loop (rightDlist l, dataDlist l::A) (l::visited) in loop (rightDlist (leftDlist L), nil) nil endさらに、循環リストは、リストの末尾からも辿ることができるので、 以下のより効率よい自然なコードが可能である。
fun toList L = let fun loop (l,A) visited = if member l visited then A else loop (leftDlist l, dataDlist l::A) (l::visited) in loop (leftDlist L, nil) nil endまた、循環リストのリスト表現を逆順のリストとする定義すると、 以下の関数となる。
fun toListL L = let fun loop (l,A) visited = if member l visited then A else loop (rightDlist l, dataDlist l::A) (l::visited) in loop (rightDlist (leftDlist L), nil) nil end対応する循環リストへの変換は、
fun fromListToDlistL L = foldl (fn (x,y) => (insert x y;y)) (ref NIL) L
問 8.8
2つの循環2重リストを連結する関数
concatDlist : ’a dlist -> ’a dlsit -> unit
を定義せよ.ただし,連結の結果は,どちらのリストから見ても,セルを右にたど ると,以前のセルの後に他の循環2重リストのセルが付け加えられているようにせ よ.
解答例 以下にコード例を示す。
   fun concatDlist D1 D2 =
       case (D1, D2) of
         (ref NIL, _) => D1 := !D2
        | (_, ref NIL) => D2 := !D1
        | (ref (CELL{left=d1l as ref (CELL{right=d1lr,...}),...}),
           ref (CELL{left=d2l as ref (CELL{right=d2lr,...}),...})) =>
           let
             val d1lCell = !d1l
             val d1lrCell = !d1lr
           in
             (d1l := !d2l;
              d1lr := !d2lr;
              d2l := d1lCell;
              d2lr := d1lrCell)
           end
問 8.9
以下の関数を定義せよ.
- 
1. 
循環2重リンクリストをコピーする関数 copyDlist. 
- 
2. 
与えられた関数を循環2重リンクリストの各要素に適用して得られる値を要素 とする,新しい循環2重リンクリストを生成する関数 mapDlist. 
- 
3. 
リストの foldr および foldl に相当する関数 foldrDlist および foldlDlist. 
解答例 これら関数の適切な定義には、以下の点を含む種々の注意深い考察が必要である。
- 
• 
循環構造を辿る際の終了条件の適切な判定 
- 
• 
leftおよびrightフィールドをたどると自分自身に戻ってくる CELLへの参照型データの作成 
以下に、これら2点を考慮したコード例を示す。なお、copyDlistは mapDlistとほぼ同様なコードであり、後者を使って定義している。
   fun mapDlist f d =
       let
         fun newElem x nil = NONE
           | newElem x ((h,newH)::t) =
             if x = h then SOME newH
             else newElem x t
         fun copy l copied =
             case l of
               ref NIL => ref NIL
             | ref (CELL{left, right, data}) =>
               (case newElem l copied of
                  NONE =>
                  let
                    val newL = ref NIL
                    val copied = (l, newL)::copied
                    val l = copy left copied
                    val r = copy right copied
                  in
                    (newL := CELL{left = l, right = r, data = f data};
                     newL)
                  end
                | SOME newL => newL
               )
       in
         copy (rightDlist (leftDlist d)) nil
       end
   fun copyDlist d = mapDlist (fn x => x) d
   fun foldrDlist F z d =
       let
         fun member x nil = false
           | member x (h::t) = x = h orelse member x t
         fun f d z visited =
             if member d visited then z
             else F (dataDlist d, f (rightDlist d) z (d::visited))
       in f (rightDlist (leftDlist d)) z nil
       end
   fun foldlDlist F z d =
       let
         fun member x nil = false
           | member x (h::t) = x = h orelse member x t
         fun f d z visited =
             if member d visited then z
             else f (rightDlist d) (F (dataDlist d, z)) (d::visited)
       in f (rightDlist (leftDlist d)) z nil
       end