- ベストアンサー
common lispのプログラミングについて
- common lispのプログラミングについて色の英単語クイズをするプログラムが作りたいです。
- 現在のプログラムは汎用性がなく末尾再帰などの手法がわからず困っています。
- アドバイスをいただけると助かります。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
ああそうか、そっちのロジックに乗って、こっちのコードの方が分かりやすいかな。 ローカル関数使用を止めて、そちらのロジックに則ってSchemeで書きなおしたのがこれです。 (define (quiz) (display "=====hi!=====\n") ; set!(Common Lispだとsetq)は使わずletを使う (let ((cc '((ki . yellow) (ao . blue) (aka . red) (cha . brown) (murasaki . purple)))) (quiz-tr cc))) ; quiz-trにccを渡す (define (quiz-tr lst) ; 比較条件が少ないならifを使った方がスマート ; 空リスト精査ならnull?(Common Lispだとnull)を使う (if (null? lst) (display "bye.") (let ((q&alist (car lst))) ; ここで問題を出力 (display (car q&alist)) (let ((input (read))) ; ここで末尾再帰 ; 出力した後に引数リストのcdrをquiz-trに手渡す (cond ((eq? (cdr q&alist) input) (display "correct!\n") (quiz-tr (cdr lst))) ; ここで末尾再帰 ; 間違った場合、同じ問題を出すので、出力後、引数リストはそのままで再帰呼び出し (else (display "wrong.\n") (quiz-tr lst)))))))
その他の回答 (2)
- cametan_42
- ベストアンサー率62% (162/261)
残念ながら今手元にCommon Lispがないんで、代わりにScheme使います。 まあ、このレベルならどっちも大差ないんでいいでしょう(笑)。 要するにそんなに移植に苦労しないと思います。 まず、末尾再帰したい、って事なんですが、基本的には、です。 実はこう言う「ゲーム」みたいに入出力が絡むとあんま上手く、っつーか 綺麗に書けないんですよね(笑)。 普通の手続き型言語ですと、まあ、C言語入門レベルで良く味わうでしょうが、 printf命みてぇな(笑)そう言う状態になりますが、関数型でのプログラミング だと逆に、如何に入出力しないか、的なカンジがある程度出てくるんで、こう 言うゲーム関係だとある意味苦手なんですよね。 あと、気になった部分だと 1. setqはなるたけ使わない。letで束縛する方がlispっぽい 2. princとかterpri使う代わりにformat関数の方がイマっぽい 3. 連想リスト使うならハッシュを使用した方がイマっぽい くらいですかね。 んで、Schemeだと末尾再帰用構文に名前付きletってのがあってそれ使うんですが、 Common Lispには無いんで、敢えてletrec(Common Lispで言うとlabels)使って 書いてみました。実行環境はSchemeだったらPLT http://racket-lang.org/ でも試してみれば良いでしょう。 (define (quiz) ; 再帰用ローカル関数定義 (letrec ((quiz-tr ; Common Lispにはlabelsと言う同じ再帰用構文がアリ (lambda (lst) (if (null? lst) ;再帰脱出条件 (display "bye.\n") (let ((q (car lst))) ; この辺ちとインチキ。 ; Schemeのfor-eachはCLだとmapc? ; このletはここで実行させるのが目的で束縛は意味がない。 ; 束縛された値は無意味(CLだとTかNILになる筈)。 (let ((output (for-each display `(,(car q) "?\n")))) ; こうやって入力を変数に代入するのはLisp以外でも良く見られるテクニック (let ((input (read))) ; ここでtestで判定結果束縛しちゃう ; (もちろんcond本体でやってもよし) (let ((test (eqv? input (cdr q)))) ; condは暗黙のbegin(progn)があるので、最後の節は末尾再帰になる。 (cond (test (display "correct!\n") (quiz-tr (cdr lst))) ; 末尾再帰 (else (display "wrong.\n") (quiz-tr (cdr lst)))))))))))) ;末尾再帰 ; 一行出力して (display "=====hi!=====\n") ; ローカル関数呼び出し (quiz-tr '((ki . yellow) (ao . blue) (aka . red) (cha . brown) (murasaki . purple))))) まあ、また何か分からん事あったら質問してみてください。
- Tacosan
- ベストアンサー率23% (3656/15482)
この場合の「汎用性」ってなんだろ.... 単純に「リストの各要素に対してなんかする」なら mapcar など map一族を使うと簡単かな.
補足
そうですね。。 えっと、上記のイメージのようなのを自動的に行いたいのです。 まずスタートし、日本語の問題が出てくる(ki)、そしてそれに対して答えをユーザが入力する(yellow)そして合っていたらcorrect!と表示し次の問題に進み、間違えたらwrong.と表示し、もう一度同じ問題が出される。そして、5問終わったらプログラム終了。その繰り返し?のためにloopではなく再帰を使いたいのですが、上手く出来ないということです。
お礼
ありがとうございます! 参考にしてみます!