他のことをする前に、入手可能なLispの入門テキストを見てください。
[dons code-review 帽子]
(defun prefix (a y) (cond ((null y) nil)
(t (cons (cons a (car y)) (prefix a (cdr y))))))
(setq result prefix(a (cons 1 2)))
(print result)
第一に、これらの定義は、散文の説明がそうすべきだと言っていることを実行しません。再帰関数の一部として印刷する必要はありません。を印刷しますresult
が、それはprefix
ed リスト全体がまとめられた後です。関数prefix
も新しいシンボルを返すのではなく、ペアを返します。
それらを印刷するために中間値を設定する必要はありません。Lisp関数は暗黙的に戻り、なしで構成できますsetq
(defun prefix (a y)
(cond ((null y) nil)
(t (cons (cons a (car y))
(prefix a (cdr y))))))
(print prefix(a (cons 1 2)))
Lisp は完全にプレフィックス表記であり、関数名は呼び出し括弧内に表示されます。
...
(print (prefix a (cons 1 2)))
a
あなたのprefix
呼び出しでは、バインドされていない変数です。a
「記号」'a
または「キーワードa
」を使用するつもりだったと思います:a
。単に を渡すa
と、Lisp はその名前を変数として評価しようとし、値が割り当てられていない場合は失敗します。
...
(print (prefix 'a (cons 1 2)))
の 2 番目の引数prefix
は適切なリストではありません。それはペアです。違いを確認するには、両方のコンストラクトの基になるポインター構造を確認する必要があります。
(cons 1 2) => [ 1 | 2 ]
(list 1 2) => [ 1 | ]
\
[ 2 | ]
\
NIL
関数が適切なリストを期待している場所でペアを使用しようとすると、ペア#<TYPE-ERROR expected-type: LIST datum: 2>
の末尾がリストではないのに対し、 a の末尾は であるためlist
、エラーが発生します。
(defun prefix (a y)
(cond ((null y) nil)
(t (cons (cons a (car y))
(prefix a (cdr y))))))
(print (prefix 'a (list 1 2)))
この時点で、実行可能なプログラムができました。(print (prefix 'a (list 1 2)))
その関数を定義した後に REPL で評価すると、
CL-USER> (print (prefix 'a (list 1 2)))
((A . 1) (A . 2))
((A . 1) (A . 2))
出力が重複していることに注意してください。これは、Lisp REPL が、評価した任意のフォームの戻り値を自動的に出力するためです。これは、実際にprint
完全にドロップできることを意味します。
CL-USER> (prefix 'a (list 1 2))
((A . 1) (A . 2))
あなたが望んでいたことを行う (最初の引数を接頭辞としてシンボルの新しいリストを作成する) には、実際にはいくつかの文字列操作を使用intern
してシンボルを作成する必要があります。
(defun prefix (a y)
(cond ((null y) nil)
(t (cons (intern (format nil "~a~a" a (car y)))
(prefix a (cdr y))))))
(prefix 'a (list 1 2))
今すぐ返す必要があります(A1 A2)
。Common Lisp は大文字と小文字を区別せず、自動的に小文字の記号を大文字に変換することに注意してください。
再帰は優れた学習ツールであり、末尾再帰はSchemeの主要な反復構造ですが、通常、可能であれば反復的に行うことをお勧めします。CL は末尾呼び出しの最適化を保証しないことに注意してください。したがって、これは通常、loop
またはmapcar
(場合dolist
によっては) を使用することを意味します。
(defun iterative-prefix (a a-list)
(loop for elem in a-list
collect (intern (format nil "~a~a" a elem))))
(defun map-prefix (a a-list)
(mapcar
(lambda (elem) (intern (format nil "~a~a" a elem)))
a-list))
これらはどちらも再帰バージョンと同じ出力を提供しますが、十分に長いリストを指定した場合、スタック領域が不足するという同じリスクはありません。
CL-USER> (prefix 'a (make-list 100000 :initial-element 1))
Control stack guard page temporarily disabled: proceed with caution
Control stack guard page temporarily disabled: proceed with caution
; Evaluation aborted on #<SB-KERNEL::CONTROL-STACK-EXHAUSTED {1004D674F3}>.
CL-USER> (iterative-prefix 'a (make-list 100000 :initial-element 1))
(A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 A1 ...)
CL-USER>