Lambda lisp中的布尔函子

Lambda lisp中的布尔函子,lambda,lisp,common-lisp,functor,higher-order-functions,Lambda,Lisp,Common Lisp,Functor,Higher Order Functions,我发现自己处于一种需要将几个谓词组合成一个谓词的情况。有没有一种标准的方法可以做到这一点,类似于恭维 假设有几个简单谓词(例如,is-fruit-p,is-red-p,growth-on-trees-p等)和一个对象列表,必须使用多个谓词从中筛选出子集。实现这一目标的最佳方法是什么: (remove-if #'is-fruit-p (remove-if #'is-red-p (remove-if #'grows-on-tree

我发现自己处于一种需要将几个谓词组合成一个谓词的情况。有没有一种标准的方法可以做到这一点,类似于
恭维

假设有几个简单谓词(例如,
is-fruit-p
is-red-p
growth-on-trees-p
等)和一个对象列表,必须使用多个谓词从中筛选出子集。实现这一目标的最佳方法是什么:

(remove-if #'is-fruit-p 
           (remove-if #'is-red-p 
                      (remove-if #'grows-on-trees-p list-of-objects)))

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

宏可以如下所示:

(defmacro combine-predicates (combine-func &rest preds)
  (let ((x (gensym)))
    `(lambda (,x) (,combine-func ,@(loop for p in preds 
                      collecting `(funcall ,p ,x))))))
你可以这样使用它

(remove-if (combine-predicates and 
                               #'is-fruit-p 
                               #'is-red-p 
                               #'grows-on-trees-p) obj-list)

你确定一种特殊的语法真的会有帮助吗?考虑下面的

(lambda (x)
  (and (is-fruit-p x)
       (or (grows-on-tree-p x)
           (is-red-p x))))
现在是更一般的

(lambda (x)
  (and (is-fruit-p x)
       (or (grows-on-tree-p x)
           (eq (color x) 'red))))

即使你为谓词建立了一种特殊的语法,你认为增加的语言复杂性值得你得到的刚性吗?例如,您是否要定义一个谓词
#“weights-justice-five-ounces-p
?“重量不超过6.5盎司(含6.5盎司)p”怎么样

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

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

(remove-if (lambda (x) (or (is-fruit-p x)
                           (is-red-p x)
                           (grows-on-trees-p x)))
           list-of-objects)
少写,少读,无需额外学习,琐碎的参数化

例如,假设您想要一个水果列表,该列表的颜色与您(在
我的
中)的颜色相同,重量相同或可能更重

(remove-if-not (lambda (x) (and (is-fruit-p x)
                                (eq (color x) (color mine))
                                (>= (weight x) (weight mine))))
               objects)

使用第一类函数的方法:

(defun complement (func)
  (lambda (x) (not (funcall func x))))

(defun conjoin (pred1 pred2)
  (lambda (x) (and (funcall pred1 x) (funcall pred2 x))))

(defun disjoin (pred1 pred2)
  (lambda (x) (or (funcall pred1 x) (funcall pred2 x))))
你可以从中产生

(remove-if (conjoin #'is-fruit-p (conjoin #'is-red-p #'grows-on-trees-p)) list-of-objects)

在可安装库中提供了较高阶的函数,如
disjoin
conjoin


谢谢,您认为删除
funcall
#“
s怎么样?我不确定funcall对性能有何影响,因此如果您愿意,可以删除funcall。事实上,我担心传球(lambda(x)(…)不起作用,但它确实起了作用,至少在sbcl中是这样。但是路过的#’(lambda(x)(…)没有。如果不使用旧的lambda语法,我认为可以删除funcall。除非您想在编译时使用一些编译时变量来设置谓词函数。请注意,如果您使用元实用性,此函数已经作为
连接
(defun-compaign(person&optional(stream t))(format-stream“Hello,~a,您今天看起来真是太棒了!”person)存在了。
我怀疑
(如果(is-red-p is-FROUT-p中的任何一个)列表,则删除该列表)
很难阅读。我也不介意使用与您的示例类似的代码,只是我有一个更大的
循环
,其中我需要使用
移除id
is-a-p
,以及
is-a-p
is-b-p
,这让我想到可以使用一些缩写。Co你能详细说明一下如何参数化你的最后一个例子吗?谢谢,这可能是最好的答案。
(defun complement (func)
  (lambda (x) (not (funcall func x))))

(defun conjoin (pred1 pred2)
  (lambda (x) (and (funcall pred1 x) (funcall pred2 x))))

(defun disjoin (pred1 pred2)
  (lambda (x) (or (funcall pred1 x) (funcall pred2 x))))
(remove-if (conjoin #'is-fruit-p (conjoin #'is-red-p #'grows-on-trees-p)) list-of-objects)
CL-USER> (ql:quickload "alexandria")
...
CL-USER> (remove-if (alexandria:disjoin #'zerop #'oddp #'minusp)
                    '(0 -1 1 -2 2))
=> (2)