• ベストアンサー

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)))))

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

  • ベストアンサー
回答No.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な人たちはこの題意ですとこっちの方をより好むかもしれません。

noname#182748
質問者

お礼

詳しい回答ありがとうございます。大変助かりました。ものすごく短くなって驚きました。

その他の回答 (1)

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

Common Lisp なんか忘れちゃったけど, なんとなく ((ls lst (cdr lst)) はおかしい気がする. それにしても, なんかメッセージくらい出ないの?

noname#182748
質問者

お礼

回答ありがとうございました。

関連するQ&A