- ベストアンサー
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)))))
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
ふむ。「反復で」って事ですね。 エラーの原因はこれらです。 (defun dot (lst) (let ((c 0)) (do ((ls lst (cdr ls))) ; cdrを取るのはlsではなくてls。また閉じ括弧の数が足りない。 ((null ls) c) ; lst の cdr を取ればここが意味が分からなくなる。 (if (eq 'a (car ls)) (incf c) ; doは破壊的操作がベースなので incf を使うべき c)))) ; (+ c 0) は書かなくて良い。 ただし、これはかなり無駄がある気がします。Lispやってる人はあまりdoの本体部は使わないでしょう。これはどっちかと言うとCなんかをやってる人の手癖でしょうけど、このお題ならカウンターで全部処理しちゃうのが、「オツな」やり方だと思います。letを使ってcの初期化はしません。 (defun dot (lst) (do ((ls lst (cdr ls)) (c 0 (if (eq 'a (car ls)) ; cもカウンター化して、更新条件をぶち込む。 (+ c 1) c))) ((null ls) c))) オリジナルのロジックに近い考え方ですと、doよりむしろdolistの方が適するかもしれません。 (defun dot (lst) (let ((c 0)) ; let で c を初期化 (dolist (x lst c) ; これで x が lst の car に設定される。返り値は c 。 (when (eq 'a x) ; c の据え置きに計算上特に興味が無い場合、 when を使うと良い。 (incf c))))) あと、反復だと、Common Lispな人たちならdo/dolistを使うよりloopを好むかもしれません。 (defun dot (lst) (loop for c in lst if (eq c 'a) count c)) あるいは (defun dot (lst) (loop for c in lst when (eq c 'a) count c)) とか。 ちょっとLispのコードに見えないですけど(笑)、これが一番短いですね。Common Lispな人たちはこの題意ですとこっちの方をより好むかもしれません。
その他の回答 (1)
- Tacosan
- ベストアンサー率23% (3656/15482)
Common Lisp なんか忘れちゃったけど, なんとなく ((ls lst (cdr lst)) はおかしい気がする. それにしても, なんかメッセージくらい出ないの?
お礼
回答ありがとうございました。
お礼
詳しい回答ありがとうございます。大変助かりました。ものすごく短くなって驚きました。