リストを逆順にする関数(LISP)の仕組みとは?

このQ&Aのポイント
  • 「初めての人のためのLISP[増補改訂版]」のP150のリストを逆順にする関数について詳しく説明します。
  • 関数の仕組みは再帰を使い、リストの要素を逆順につなげていく方法です。
  • rplacd関数を使ってリストのポインタを逆転させ、最終的にリストを逆順にします。
回答を見る
  • ベストアンサー

リストを逆順にする関数(LISP)

「初めての人のためのLISP[増補改訂版]」のP150のリストを逆順に関数がよくわかりません。 以下がその関数です。 (defun nreverse (x) (nrev2 x nil)) (defun nrev2 (x r) (cond ((null x) r) (t (nrev2 (cdr x) x) (rplacd x r) ))) xがnilになるまで再帰を繰り返し、((null x) r) で再帰を戻りますがなぜs (rplacd x r)でリストが逆順になるんでしょうか。例えばxを(a b c)とすると x:(a b c) r:nil ↓ x:(b c) r:(a b c) ↓ x:(c) r:(b c) ↓ x:nil r:(c) ↓ rplacd (c) (b c) ↓ rplacd (b c) (a b c) ↓ rplacd (a b c) nil となるのですが、これじゃあ全然リストは逆順になりませんよね。 誰が教えてください、お願いします。 ちなみにrplacd は第一引数のcdrを第二引数に変換する関数です。

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

「'(c)と'(b c)のcdrのcは実体は同じということでしょうか?」 という聞き方だと (eq (car '(c)) (cadr '(b c))) は常に t を返すか? と解釈したくなる (これは正しい) んだけど, それはおそらく「本来聞きたいこと」じゃないよね? 「'(c) で表される consセルと '(b c) の cdr である consセルの実体が同じかどうか」ということであればは一般には不定 (等しいこともあれば等しくないこともある). つまり (equal '(c) (cdr '(b c))) => t (eql '(c) (cdr '(b c))) => t または nil (eq '(c) (cdr '(b c))) => t または nil ということになる. もっとも, 今の場合には eq の意味でも同じであることが (プログラムの作り方から) 保証される.

puntero
質問者

お礼

なんとなくわかりました。 ありがとうございます。

その他の回答 (3)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

質問文にある関数はB子さんが解答したもので、正しく動かないとK先生に指摘されたものではないですか? それをおいてもこの関数は一つのリストを共有して直接書きかえているので、質問文の後半にあるめも書きのように 考えてしまうと混乱してしまうと思います。 #2の方の回答で示されているリンク先にある図をよく見て追いかけてみてください。 つか前の質問どうしたの?

puntero
質問者

補足

正しく動かないけどリストの逆順は行われている という説明だったので本質的には変わらないと思います

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.2
puntero
質問者

補足

おお!まさに聞きたい説明です! ありがとうございます。 このページの 3.返り値 で (rplacd '(c) '(b c)) のところで carがcのセルのcdrからcarがbのセルに繋がり、そのセルのcdrはまた同じcarがcのセルに繋がっていますよね。これってつまり '(c)と'(b c)のcdrのcは実体は同じということでしょうか?

noname#217196
noname#217196
回答No.1

rplacdの第二引数からcarで取り出す処理を忘れてる(誤植?)のではないでしょうか。 rplacd(x car(r)) ならうまく動きそう。

関連するQ&A

  • Lispでリストの中身もすべて反転する関数

    リストの中身をもすべて反転する関数を作っているのですが、 reverse関数を自分で実装はできたのですが、上記のような使用を持つ関数を作れません。どうぞどのようにしたらよいか教えていただけないでしょうか? ちなみに自分で作ったreverseはこれです。 (defun my-reverse (n) (if (null n) nil (append (my-reverse (cdr n)) (list (car n))))) 作りたい関数では以下のようになります。 (make-reverse '(a (b (c d))(e (f g)))) (((g f) e)((d c) b) a)

  • 「初めての人のためのLISP[増補改訂版]」で

    「初めての人のためのLISP[増補改訂版]」のP.46の練習問題をやっていくと (setq A nil) nil (setq B '(87 58 90)) (87 58 90) (setq C '(I B M)) (I B M) (null t) nil (null A) t (null (null A)) nil (cadr B) 58 (+ (car B) (caddr B)) 177 (cadr C) B (set (car C) (cdr B)) (58 90) (car C) I (atom C) nil となりますが、 なぜ (atom C) でnilが返ってくるのですか? "C"はアトムではないのですか?

  • LISPでatomの数を数える

    XLISPでlistの中のatomの数を数えたいんです。 下のようにlistの中のatomだけを抜き出してリストにすることはできました。 (DEFUN F1(L) (COND((NULL L) NIL) ((LISTP(CAR L))(F1(CDR L))) (T (CONS (CAR L)(F1(CDR L)))) ) ) このコードを実行すると次のようになります。 (F1 '((A B) C D (E F) G)) (C D G) 後はこれをlengthで数えるだけだと思うのですがそのやり方が分かりません。 それとももしかしてSETQで変数を設定して Tのところで値を1つずつ足していくのでしょうか?

  • emacsでcmmon lispのプログラムを作成します。

    emacsでcmmon lispのプログラムを作成します。 my-equal(A, B)= if A is an atom then if B is an atom then (eq A B) else if B is an atom then nil else if (car A)=(car B) then (cdr A)=(cdr B) else nil というのです。自分が考えたのは、 defun my-equal(x, y)= (cond ((atom x) (atom y)) (eq x, y) (atom) (t, nil) ((car x)=(car y) (cdr x)=(cdr y)) (nil)) というのでよろしいのでしょうか? また、4行目(この全文の)の意味がいまいち分かりません。

  • Lispについてわからないことが(Scheme)

    あるLispの勉強ソフトで、 「関数lを『引数としてxを受け取ると、xの要素の数を返す関数』として定義しなさい。」 という問題があるのですが、私は以下のようにしました。 (define l (lambda (x) (if (= x null?) 0 (+ 1 (l (cdr x)))))) しかしこれだとオーバーフローと表示されて強制終了されてしまいました。 そこで答えをネットで検索したところ以下のものが見つかりました。 (define l (lambda (x) (cond ((null? x) 0) (else (+ 1 (l (cdr x))))))) これが正解なようですが、この2つのリストの違いがわかりません。 初歩的なことですがifの使い方を間違っているんでしょうか?

  • common lispのコード

    リスト中の要素aの数をカウントするプログラムを反復で書いたのですが、実行しようとすると停止してしまいます。何が悪いのでしょうか?教えてもらえませんか? (defun dot (lst) (let ((c 0)) (do ((ls lst (cdr lst)) ((null ls) c) (if (eq 'a (car ls)) (+ c 1) (+ c 0)))))

  • Lispにおける最大値関数

    Lispで括弧の入れ子の中身も含めた最大値を求める関数を自分なりに作ったのですが、条件によってはうまくいきません。 なぜだか教えていただけないでしょうか? (defun max1 (n) (cond ((atom n) n) (t (if (null (cdr n)) (max1 (car n)) (progn (let ((local_max (max1 (cdr n)))) (if (> (car n) local_max) (car n) local_max))))))) > (max1 '(1 2 6 (3 4))) 6 > (max1 '(1 2 (6) ((3 4)))) >: (6) is not a REAL

  • LISPのプログラミングについて

    リストと数nを引数として、リストの(n-1)番目の要素を返す関数を 再帰を使って定義するにはどうすればいいでしょうか?

  • lispのwhile

    lispの特殊形式whileを以下のように定義します。 (while 判定条件 本体…) 第一引数である判定条件を評価し真ならば本体を評価しもういちど判定条件を評価、偽ならば本体を評価しない。 この時次のコードでよくわからない部分があります (defmacro image (var list &rest forms) `(let (($list$ ,list) ($r$ nil) (,var nil) ) (while ($list$ (nreverse $r$)) (setq ,var (pop $list$)) (push (progn ,@forms) r) ))) ($list$ (nreverse $r$)) この文は 偽(つまりnil) になりえるのですか? $list$はpopを繰り返すのでループを繰り返せばnilになるでしょう。 しかし (nreverse $r$) はpushを繰り返すのでnilにはなりえないと思います。 また、もしnilになりえたとしても (while (nil nil)) は (while (nil)) と同値なのでしょうか? ちなみにこれはlispの参考書のコードそのままです。 読み進めていくうちにだんだん難しくなってきました。 もうどれだけ考えてもわからないので、気持ち悪い思いはしながらもどんどん先に進んでいます。 こんな勉強法でいいんでしょうか? 不安になります。

  • Emacs Lisp: consセルと引用符?

    お世話になります。 Emacs Lispについて勉強しています 今は、リスト、consセルについて勉強しています。 以下、拙い質問になるかと思いますが、よろしくお願いします。 Lisp Interactionモードのバッファに、 '(1 2 3) というリストを書いて行末でC-jを押下すると (1 2 3) という式を返します。 しかし、 (1 2 3) という式を書いて行末でC-jを押下すると Debugger entered--Lisp error: (invalid-function 1) というエラーになります。 これは、1が関数、2と3が引数として評価されるからですね。 さて、リストではなく「consセル」を作るとします。 (1 . 2) と書いてC-jを押下すると、やはり Debugger entered--Lisp error: (invalid-function 1) というエラーになります。 '(1 . 2) であれば (1 . 2) と、正しくconsセルが出来ます。 '(1 . nil) であれば (1) というリストを返します。 これは、cdr部がnilであるconsセルはリストになるからですね。 では、3と、「1とnilからなるリスト」のconsセルを作って、結果的に(3 1)というリストにしようとします。 '(3 . '(1 . nil)) この場合は、予想に反して (3 quote (1)) となります。 '(3 . (1 . nil)) であれば、 (3 1) となります。一方、 (3 . (1 . nil)) とすると、 Debugger entered--Lisp error: (invalid-function 3) となります。 まとめると、 3と、「1とnilからなるリスト」のconsセルを作って、結果的に(3 1)というリストにしようとした場合は、 '(3 . (1 . nil)) のように外側のconsセルはクォートし、内側のconsセルはクォートしない、ということになりますね。 このクォートの振る舞いの違いはなぜでしょうか。 よろしくお願いします。

専門家に質問してみよう