避免 funcall 的双重调用

Avoiding double call of funcall

Consider the following function definition in Lisp:

(defun Fct(F L)
    (cond
        ((null L) nil)
        ((funcall F (car L)) (cons (funcall F (car L)) (Fct F (cdr L)) ) )
        (T nil)
    )
)

Give a solution to avoid the double call (funcall F (car L)).You wil not use set,setq,setf. Justify the answer.

我是这样重新定义函数的:

(defun Fct2(F L)
    (funcall #'(lambda (x)
                    (cond
                        ((null L) nil)
                        (x (cons x (Fct2 F (cdr L)) ) )
                        (T nil)
                    )
                )
        (F (car L))
    )
) 

我工作了,但是我看不到后面有没有double call了。我也看到有人用另一种方式做到了:

(defun redefine(f l)
    (funcall #' (lambda (x)                    
                        (cond 
                            ((null l) nil)
                            (x (cons x (Fct f (cdr l))))
                            (t nil)
                        )                   
                )
                (funcall f (car l))
    )
)

(里面用的是老Fct)

但我认为 Fct2 是继续进行的好方法。我想听听一些意见。

函数fct接受一个函数f和一个列表L作为参数 和 returns L 元素的 t 列表,其计算结果为 f un
的真值 直到 L 耗尽,或者元素对 F.

的计算结果为 false

例如:

(fct #'plusp '(1 2 -3 4 10)) => (t t),
(fct #'listp '((1 2 3) 4 '(a))) => (t),
(fct #'listp nil) => nil.

函数 fct2redefine 不满足此行为。

为了避免多次计算一个表达式, 简单地将表达式的计算结果绑定到一个符号。 考虑以下实现预期结果的实现:

(defun fct-2 (func list)
  (when list
    (let ((head (funcall func (car list))))
      (when head
        (cons head (fct-2 func (cdr list)))))))

when 当您有一个没有 else 部分的 if 表单时特别有用。 在fct-2中,我们将(funcall func (car list))的结果绑定到 head 我们稍后会用到。

旁注:

  1. Commonlisp 为函数和变量提供了独立的命名空间,因此我们可以毫无问题地使用像 list 这样的名称作为变量名,这可以使程序更清晰而不是名称 像列表的 L
  2. 查看 https://mumble.net/~campbell/scheme/style.txt and https://lisp-lang.org/style-guide/ 编写和格式化(通用)lisp 程序的指南。