質問するログイン新規登録
LISP

LISPはプログラミング言語の一種であり、関数型言語に分類されています。 特徴として、括弧を多様する独特の構文を持ちます。

Q&A

解決済

2回答

4368閲覧

LISPのエラーが解決できない

subaru-k

総合スコア19

LISP

LISPはプログラミング言語の一種であり、関数型言語に分類されています。 特徴として、括弧を多様する独特の構文を持ちます。

0グッド

1クリップ

投稿2020/05/12 08:45

0

1

簡単な英文(肯定文)を疑問文にする以下のプログラムを作成しました。

入力例:(question '(this is a simple lisp function))
出力例:(is this a simple lisp function ?)

LISP

1(defun question (arg) 2 ( 3 (let ( (be) (a ()) ) 4 (loop 5 (cond ( (equal be (car arg)) (return arg) ) ) 6 (setq be (car arg)) 7 (setq arg (cdr arg)) 8 (cond ( (or (equal 'am be) (equal 'is be) (equal 'are be) 9 (equal 'was be) (equal 'were be) ) 10 (setq arg (cons be (append (reverse a) arg))) 11 ) 12 ) 13 (setq a (cons be a) ) 14 ) 15 ) 16 ) 17)

すると以下のエラーが表示されました。

*** - SYSTEM::%EXPAND-FORM: (LET ((BE) (A NIL)) (LOOP (COND ((EQUAL BE (CAR ARG)) (RETURN ARG))) (SETQ BE (CAR ARG)) (SETQ ARG (CDR ARG)) (COND ((OR (EQUAL 'AM BE) (EQUAL 'IS BE) (EQUAL 'ARE BE) (EQUAL 'WAS BE) (EQUAL 'WERE BE)) (SETQ ARG (CONS BE (APPEND (REVERSE A) ARG))))) (SETQ A (CONS BE A)))) should be a lambda expression The following restarts are available: ABORT :R1 Abort main loop

このエラーの意味と、どうすれば直るのかを回答していただけると幸いです。
環境は、Windows10で、バーチャルボックス上でubuntuを起動しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

んん〜。
ANSI Common Lispユーザーがなんて言うか、と言うのは難しい問題だけど、少なくとも、モダンな「関数型プログラミング」の観点から言うとsetqの多用はどうだろうか、ってのがある。
関数型プログラミングだと「なるたけ代入は避ける」。
少なくとも同じLispユーザーでもSchemeユーザーにはその傾向がある。

例えばこんなコードはどうだろう。

Lisp

1(defun question (arg) 2 (let ((be (catch 'result 3 (reduce #'(lambda (y x) 4 (if (member x arg :test #'eq) 5 (throw 'result x) 6 y)) 7 '(am is are was were) :initial-value nil)))) 8 (when be 9 `(,be ,@(remove be arg) ?)))) 10

これでも要求仕様は満たすだろう。

Lisp

1CL-USER> (question '(this is a simple lisp function)) 2(IS THIS A SIMPLE LISP FUNCTION ?) 3

condorequalで場合分けするより、ANSI Common Lispにはmemberと言う便利な関数がある。
こいつは第1引数が第2引数として与えられたリストの要素として含まれているかどうかを調べる。
含まれた場合は第1引数を先頭とした第2引数の残りのリストを返し、そうじゃない時はnilを返す。

Lisp

1CL-USER> (member 'am '(this is a simple lisp function) :test #'eq) 2NIL 3CL-USER> (member 'is '(this is a simple lisp function) :test #'eq) 4(IS A SIMPLE LISP FUNCTION) 5

memberではキーワード引数:testで等価判定関数を指定できる。このケースでは、比較対象はシンボルなんで、一番高速なeqで比較可能だ(これはC言語で言うポインタ比較となる)。

関数reduceは誤解を恐れずに言うと非破壊的なfor文だ。あるいはその役目を果たす。
与えられたリスト、この場合だと'(am is are was were)の先頭からmemberの第1引数へと渡していき、それらがリストarg内に含まれているかどうかを調べていく。
ここは基本的には、例えばPythonで言うとこういう形式に近い。

Python

1for x in ['am', 'is', 'are', 'was', 'were']: 2 member(x, arg)

特殊形式catchthrowは脱出の為の構文だ。もうちょっと言うとジャンプ構文で、throwで「投げた」計算結果をcatchが受け取る。文字通りだ。
今、'(this is a simple lisp function)と言うリストに対してリスト'(am is are was were)の先頭要素から順繰りにそれが与えられたリストの要素に含まれているかどうかを調べていってるわけだ。
'amは含まれてないんで棄却だが2番目の'isは含まれている。そして、2番目の'isが含まれている、と分かった時点で、残りの'(are was were)は調べなくても良い、って事が決定する。
すなわち、'isを持ってreduceを止めて脱出したい。
それが故にthrow'isを投げてその外側でcatchし、それをそのままletで変数beに束縛する。
結果、変数beの内容は'isとなる。

あとは簡単だろう。beが取り得る結果は「何らかがあった」か、見つからなかった(つまりnil)か、だ。whenで変数beが非nilの時、単純には、リストargからbeをフィルタリング(remove)したモノのケツに'?を結合したリストを作り、先頭にbeconsしたモノを返せば題意を満たせる。

投稿2025/07/21 17:10

編集2025/07/21 17:15
cametan

総合スコア142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

let の外にある括弧が一個余分で、
エラーメッセージに表示されているコード全体は、
lambda式であるべきと言われてます。

lisp

1(defun question (arg) 2 (let ((be) (a ())) 3 (loop 4 (cond ((equal be (car arg)) (return arg))) 5 (setq be (car arg)) 6 (setq arg (cdr arg)) 7 (cond ((or (equal 'am be) 8 (equal 'is be) 9 (equal 'are be) 10 (equal 'was be) 11 (equal 'were be)) 12 (setq arg (cons be (append (reverse a) arg))))) 13 (setq a (cons be a))))) 14 15(print (question '(this is a simple lisp function)))

ちなみに、文字列ではなくシンボルなので出力は

(IS THIS A SIMPLE LISP FUNCTION)

投稿2020/05/12 09:36

編集2020/05/12 10:19
teamikl

総合スコア8824

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

subaru-k

2020/05/12 09:55

丁寧なご回答ありがとうございます。 理解できました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問