2017-02-14 7 views
3

私は関数の引数宣言で&restを見ると、ruby*argsと似ていると思っていました。そして私は+と同じことをするために関数sumitを書き始めました。共通リスプで `&rest` argsをどう扱うか

(defun sumit (&rest args) 
    (if (null args) 
     0 
     (+ (car args) (sumit (cdr args))))) 

が、私はそれがセグメンテーションフォールトを取得(sumit 1 2 3)を呼び出すとき、再帰は決して終わりません。 (sumit)でも動作します。

私の容疑者は(null args)の部分ですが、(eql nil args)などのようなものを変更した後でも同様のことはできません。

したがって、&rest argsを分解する正しい方法は何ですか? nilをチェックする正しい方法は何ですか?

+3

'SUMIT'は可変数の数値を引数としてとりますが、数字ではなく単一のリスト引数で呼び出す'(sumit(cdr args) ')にあります。代わりに '(apply# 'sumit(cdr args))'を使う必要があります。 – jkiiski

+0

@jkiiskiオハイオ州、そうですよ!どうも! btw、 'apply'を使わずに複数の引数にリストを展開する方法はありますか? – delta

+0

@delta:no、use APPLY –

答えて

3

(sumit (cdr args))sumitを1つの引数 - リストとして呼び出します。あなたはapplyを使用する必要が :

(defun sumit (&rest args) 
    (if args 
     (+ (car args) (apply #'sumit (cdr args))) 
     0)) 

注:

  1. この実装は末尾再帰ではありません(ANSI CLがは末尾呼び出しの最適化を必要としませんが、多くの実装がそれを提供します) 。
  2. call-arguments-limitlambda-parameters-limitをご覧ください。
  3. (reduce #'+ list-of-numbers) 、1起因上記二つの変数に、(apply #'+ list-of-numbers)、 しかしを使用することができ、リストの要素を合計するには、はるかに優れたアプローチです。
+0

注1に関して、Common Lispはテール再帰をとにかく保証しません。 – acelent

+1

@acelent:ありがとう、はい、私は知っています、編集を参照してください。 – sds

関連する問題