lisp中的布尔函子

zza*_*ndy 5 lisp lambda common-lisp functor higher-order-functions

我发现自己处于需要将多个谓词合并为一个的情况.有没有一种标准的方法来实现这一点,类似于compliment

假设有几个简单谓词(例如is-fruit-p,is-red-p,grows-on-trees-p等),并从其中的一个子集必须使用多于一个的谓词被过滤出的对象的列表.实现这一目标的最佳方法是:

(remove-if #'is-fruit-p 
           (remove-if #'is-red-p 
                      (remove-if #'grows-on-trees-p list-of-objects)))
Run Code Online (Sandbox Code Playgroud)

650*_*502 5

您确定特殊语法真的有用吗?考虑以下

(lambda (x)
  (and (is-fruit-p x)
       (or (grows-on-tree-p x)
           (is-red-p x))))
Run Code Online (Sandbox Code Playgroud)

现在稍微更一般了

(lambda (x)
  (and (is-fruit-p x)
       (or (grows-on-tree-p x)
           (eq (color x) 'red))))
Run Code Online (Sandbox Code Playgroud)

要么

(lambda (x)
  (and (is-fruit-p x)
       (or (grows-on-tree-p x)
           (eq (color x) desired-color)))) ; desired-color captured lexical
Run Code Online (Sandbox Code Playgroud)

即使您为谓词构建了一个特殊的语法,您是否认为增加的语言复杂性值得您获得刚性?例如,您要定义谓词#'weights-exactly-five-ounces-p吗?怎么样#'weights-up-to-and-including-six-and-half-ounces-p

如果您开始需要参数谓词并使用lambda表单然后使用组合器,那么您将编写更多代码而不是使用它,因为(lambda (x) ...)每个参数项都需要包装器.更重要的是,代码也将更难阅读(除了必须为谓词组合学习一个特殊的新宏).

IMO如果您传入谓词并且需要将谓词传递给其他人,那么编写和/或组合器可能是有意义的......但不是为了编写您在示例中使用的代码; 为此,我写了

(remove-if (lambda (x) (or (is-fruit-p x)
                           (is-red-p x)
                           (grows-on-trees-p x)))
           list-of-objects)
Run Code Online (Sandbox Code Playgroud)

更少写,更少阅读,没有什么额外的学习,琐碎的参数化.

例如,假设您想要一个水果列表,其颜色与您拥有的水果相同,mine并且具有相同的重量或可能更重......

(remove-if-not (lambda (x) (and (is-fruit-p x)
                                (eq (color x) (color mine))
                                (>= (weight x) (weight mine))))
               objects)
Run Code Online (Sandbox Code Playgroud)


Jus*_*ous 3

我不确定盒子里是否有这样的功能。如果您需要组合可以在编译时确定的函数,您可以编写一个宏来执行此操作。如果您必须动态检测谓词函数,您可以编写函数来执行此操作,该函数将循环抛出函数列表并累积结果,直到出现错误条件为止。

该宏可以如下所示:

(defmacro combine-predicates (combine-func &rest preds)
  (let ((x (gensym)))
    `(lambda (,x) (,combine-func ,@(loop for p in preds 
                      collecting `(funcall ,p ,x))))))
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它

(remove-if (combine-predicates and 
                               #'is-fruit-p 
                               #'is-red-p 
                               #'grows-on-trees-p) obj-list)
Run Code Online (Sandbox Code Playgroud)