2012-01-21 16 views
6

私は新しい言語としてLispを手に入れようとしています。関数の一部を渡されたリストの各要素に作用させる方法を検討しています。defunを引数としてリスト

リストの要素の1つは0です(代わりに、単に0を返す)ときは、この問題を回避する方法を学習する目的のために、私は分裂のかなり基本的な形を記述しようとしていますがcroakしていません

(defun divtest (elements) 
    (dolist (x elements) 
    (if (zerop x) 0()) 
    (/ elements))))) 
得どちら

(divtest '(20 2 5)) 

:として

は、私はこれを実行しよう

*** - /: (20 2 5) is not a number 

失敗のポイントは、関数に渡す前にリスト内の要素を "抽出"していないという事実に根ざしているようです(この場合、xは決して0に評価されないので、/ dolistは意図したとおりに動作しません)。 もし私が正しければ、誰かがこの「抽出」を実行する方法を教えてもらえますか?


注:この質問はone that I've asked earlierに関連しているが、私は前の回答のどの部分について不明確だとして、私は基本的に、さらに行くことにした。この特定の問題を意図したように、実際にそれが動作することができ

答えて

5

/は、引数として1つ以上の数値をとりますが、コードではリストを渡しています - これはうまくいきません。機能applyはここにあなたの友人です - (apply #'foo a b (list c d e))(foo a b c d e)に相当します。使用する関数と最終リストの間のapplyへの引数はオプションであるため、(apply #'/ '(20 2 5))(/ 20 2 5)に相当します。

また、ゼロを削除しようとしても機能しません。 dolistは、引数リストelementsの各項目のボディを評価していますが、実際にelementsの内容を変更することはありません。dolistの評価結果は、元の要素に再割り当てされません。

機能remove-if(およびその破壊的な対応者delete-if)があなたが探しているものです。以下は、それを使用する方法を示しています(この目的のために心配する必要はありません)。

(defun divtest (elements) 
    (apply #'/ (remove-if #'zerop elements))) 

elementsリストは、(私は関数のは、やって何を意味するのか理解想定して)その最初の要素としてゼロを持っている場合、これは正しく動作しないことに注意してください。だからあなたの代わりに何かが欲しいかもしれない

(defun divtest (elements) 
    (apply #'/ (first elements) (remove-if #'zerop (rest elements)))) 

詳細については、Hyperspecを参照してください。

+2

APPLYの代わりにREDUCEを使用 –

+0

好奇心が強い:それの有用性は何ですか? – Hugh

+0

この方法で、CALL-ARGUMENT-LIMIT(標準CL定数)の最大長だけでなく、任意の長いリストを処理することができます。 Common Lispには実装に依存する引数の最大数があります。この数は50以上でなければなりません。つまり、インプリメンテーションは50個以上の引数をサポートする必要があります。したがって、上記の関数は、数値のリストが関数/を呼び出す引数の数よりも長い実装では失敗する可能性があります。 –

0

(/ elements)の代わりに(apply/elements)を試してください。私はLispの多くの方言でうまくいくはずだと思います(?)。

+0

のように書くことができる '/'は '/' 'sのデータセルに関数を割り当てていない限り。 – Hugh

1

それとも、あなたが引用する必要があります。この

(defun divtest (elements) 
    (if (member 0 elements) 
     0 
     (apply #'/ elements))) 
1
(block exit 
    (reduce #'/ '(1 2 3 0 5) 
      :key (lambda (x) 
       (if (zerop x) 
        (return-from exit 0) 
        x)))) 
関連する問題