プログラミング再入門

プログラミングをもう一度ちゃんと勉強する読書ノート

Scheme修行 第13章 ホップ、スキップ、ジャンプ(その2)

letccの続きです。

ノート:

rember

remberでもaが不変なのでletrecを用いて再定義出来る。

> (rember 5 '(1 2 3 4 5 6 5 4 3 2 1))
(1 2 3 4 6 5 4 3 2 1)
> 

multiremberではないので最初の5だけが削除される。

rember-beyond-firstはあるアトム以降の要素を全て削除する。
remberでは探しているアトムを見つけるとcdrを返していたが、そこで空リストを返せば良い。

例を評価してみる。*1

> (let ((a 'roots)
        (lat '(noodles
               spaghetti spatzle bean-thread
               roots
               potatoes yam
               others
               rice)))
    (rember-beyond-first a lat))
(noodles spaghetti spatzle bean-thread)
> (let ((lat '(noodles
               spaghetti spatzle bean-thread
               roots
               potatoes yam
               others
               rice)))
    (rember-beyond-first (quote others) lat))
(noodles spaghetti spatzle bean-thread roots potatoes yam)
> (let ((a 'sweetthing)
        (lat '(noodles
               spaghetti spatzle bean-thread
               roots
               potatoes yam
               others
               rice)))
    (rember-beyond-first a lat))
(noodles spaghetti spatzle bean-thread roots potatoes yam others rice)
> (let ((lat '(cookies
               chocolate mints
               caramel delight ginger snaps
               desserts
               chocolate mousse
               vanilla ice cream
               German chocolate cake
               more desserts
               gingerbreadman chocolate
               chip brownies)))
    (rember-beyond-first (quote desserts) lat))
(cookies chocolate mints caramel delight ginger snaps)
> 

アトムaが見つかればそこから先を返せば良いが、特殊な事情は

  • 最後に見つかったaより先を返す。
  • 最後まで見つからなかった時にはlat全体を返す。

内部関数を呼び出す時に結果のリストを足し込んで行く方法もあるが、consではリストは逆向きに出来てしまうので、最後にreverseを呼ぶ必要がある。

letccを用いるやり方はaが見つかる度に計算を振り出しに戻し、そこから再び計算を再開させる方法。
アトムaが見つかった時点で残りのlatについてRを適用させ、その結果を以てskipを呼ぶので、latの先頭からアトムaを見つけるまでに呼ばれた関数の戻り道は全てスキップされる。

rember-upto-lastは

  1. アトムaとリストlatを引数に取り
  2. リストを値とする関数

その値は

  1. latに内部関数Rを適用した値
  2. ここで内部関数Rは
    1. リストlatを引数に取り
    2. リストを値とする関数
  3. その値は
    1. latが空の場合、空リスト
    2. latの先頭要素がアトムaと同値の場合、latの残りにRを適用しその値を以てrember-upto-lastの値とする
    3. そうでない場合、latの先頭要素とlatの残りにRを適用した値を連結したリスト

letccは再帰適用の奥から一気に最初の呼び出しの値を決める為の仕組みとして使っているので関数定義の意味を解釈する時には目印程度に思っておけば良い。

例を評価してみる。

> (let ((a 'roots)
        (lat '(noodles
               spaghetti spatzle bean-thread
               roots
               potatoes yam
               others
               rice)))
    (rember-upto-last a lat))
(potatoes yam others rice)
> (let ((a 'sweetthing)
        (lat '(noodles
               spaghetti spatzle bean-thread
               roots
               potatoes yam
               others
               rice)))
    (rember-upto-last a lat))
(noodles spaghetti spatzle bean-thread roots potatoes yam others rice)
> (let ((a 'cookies)
        (lat '(cookies
               chocolate mints
               caramel delight ginger snaps
               desserts
               chocolate mousse
               vanilla ice cream
               German chocolate cake
               more cookies
               gingerbreadman chocolate
               chip brownies)))
    (rember-upto-last a lat))
(gingerbreadman chocolate chip brownies)
> 

*1:リスト中äはリストの中ではエンコードされてしまうのでaに置き換えてあります。