首页 > 解决方案 > 避免 funcall 的双重调用

问题描述

考虑 Lisp 中的以下函数定义:

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

给出一个避免双重调用的解决方案(funcall F (car L))。你不会使用 set,setq,setf。证明答案。

这就是我重新定义函数的方式:

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

我工作,但我看不到后面是否没有更多的双重呼叫。我还看到有人以另一种方式做到这一点:

(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 是继续进行的好方法。我想听听一些意见。

标签: lambdafunctional-programmingcommon-lisp

解决方案


该函数fct将一个函数f和一个列表L作为参数,并返回一个ts 列表,其中元素的L计算结果为真值,f 直到
用完L为止,或者一个元素的计算结果为假F

例如:

(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.txthttps://lisp-lang.org/style-guide/获取有关编写和格式化(常见)lisp 程序的指南。

推荐阅读