1

リスト内の整数の数を表示するサーバーの下のコード。

(defun isNum (N)
  (and (<= N 9) (>= N 0)))

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond
       ((null list) nil)
       (((and (<= N 9) (>= N 0))) item)(incf count))
       (setq(0 + count))))))

コマンドを実行すると、エラーA' is not of the expected typeREAL'が発生します(count-numbers'(3 4 5 6 a 7 b))

4

2 に答える 2

6

あなたcondが不適切に構築され、コードの不必要な副作用を生成するビットで中置記法に切り替え、count-numbers. 仮説的には、実行された場合、そのエラーはほぼ正しいように聞こえます。パラメータで数値比較を行っています(および数値以外の入力でのエラー)。

今日はコードレビューの帽子をかぶったので、これをもう少し詳しく説明しましょう。


Lisp (これは CL、Scheme、およびすべての雑種に適用されます) は変数名や関数名でlower-case-snake-case-with-dashesはなく、 を使用します。lowerCamelCase

(defun is-num (n)
  (and (<= n 9) (>= n 0)))

Common Lisp の慣習は、述語をで始めるのではなくporで終わらせることです。スキームには、代わりに述語を終了する(IMOの方が良い)規則があります-pis-?

(defun num-p (n)
  (and (<= n 9) (>= n 0)))

((and (<= N 9) (>= N 0)))関数を呼び出す方法ではありません。本体を呼び出そうとするだけでなく、実際にその名前を使用する必要があります。これは、このコードを実行しようとした場合に発生する多くのエラーの 1 つの原因です。

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond
       ((null list) nil)
       ((num-p item) item)(incf count))
       (setq(0 + count))))))

numberp既に存在し、数値比較を試みるのではなく、その入力に対して型チェックを行います。おそらく代わりにそれを使用する必要があります。

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond
       ((null list) nil)
       ((numberp item) item)(incf count))
       (setq(0 + count))))))

((numberp item) item) (incf count))condおそらく、それが句として行うと思っていることを行いません。実際には、2 つの別個の節として扱われます。itemが であるかどうかをチェックnumberし、そうである場合はそれを返します。2番目は変数をチェックしようとし、評価された場合にincf戻ります(評価されず、評価されません)。あなたが望んでいるように見えるのは、リストに数字が見つかったときにカウンターをインクリメントすることです。つまり、その句を.counttcountincfitem

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond ((null list) nil)
            ((numberp item) 
             (incf count)
             item))
      (setq (0 + count)))))

(setq (0 + count))3つの理由で間違っている

  • 中置記法に戻ったようです。つまり、2 番目のビットが実際に0変数+count引数として関数を呼び出そうとしていることを意味します。
  • の 2 番目の部分がありませんsetq。つまり、上記をNIL暗黙的に に設定しようとしています。
  • 値を返すために実際に何も設定する必要はありません

この時点で、最終的に評価されて適切に実行されるコードが完成しました (そして、上記のエラーをスローしません)。

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list count)
      (cond ((null list) nil)
            ((numberp item) 
             (incf count)
             item))
      count)))

dolist指定されたリスト内の各要素に対して何かを行う反復構造です。つまり、リストの終了を実際に手動でテストする必要はありませんcond。また、dolist結果を収集しないため、それに戻る理由はありませんitemcountまた、で宣言した local を不必要にシャドウイングしていますlet

(defun count-numbers (list)
  (let ((count 0))
    (dolist (item list)
      (when (numberp item) (incf count)))
    count))

いつものように、これらすべてをより簡単なloop呼び出しで行うことができます。

(defun count-numbers (list)
  (loop for item in list
        when (numberp item) sum 1))

これにより、カウンターが暗黙的になり、手動で返す必要がなくなります。実際、これが特に独自の反復関数を作成する演習でない限り、Common Lisp には組み込みの がありcount-if、これはその match内の項目predicate sequence [some other options]の を受け取って返します。スタイル上の理由で具体的に名前を付けたい場合は、countsequencepredicatecount-numbers

(defun count-numbers (list) (count-if #'numberp list))

そしてそれで終わります。


結論としては、良い試みですが、さらなる質問をする前に言語ファミリー読んでみてください。

于 2012-07-10T14:36:53.223 に答える
0

それを行うさらに別の方法は次のとおりです。

(reduce
 #'(lambda (a b)
     (if (numberp b) (1+ a) a))
 '(3 4 5 6 a 7 b) :initial-value 0) ; 5

つまり、各反復で前の反復の結果 + シーケンスの次のメンバーが与えられるようにシーケンスを処理します。ゼロから開始し、シーケンス内の要素が数値になるたびに結果を増やします。

編集

申し訳ありませんが、イナイマティが言及しているのを見たことがありませんcount-if。そのほうがきっといいでしょう。

于 2012-07-11T09:38:33.227 に答える