我发现自己处于需要将多个谓词组合为一个谓词的情况下。有没有类似于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)))发布于 2013-03-18 20:06:22
我不确定盒子里有没有这样的功能。如果您需要组合可以在编译时确定的函数,您可以编写一个宏来执行此操作。如果您必须动态检测谓词函数,您可以编写function来执行此操作,该函数将循环、抛出函数列表并累积结果,直到条件为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)发布于 2013-03-18 21:40:31
你确定一个特殊的语法真的会有帮助吗?考虑以下几点
(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))))或
(lambda (x)
(and (is-fruit-p x)
(or (grows-on-tree-p x)
(eq (color x) desired-color)))) ; desired-color captured lexical即使你为谓词建立了一个特殊的语法,你认为增加的语言复杂性值得你得到的僵化吗?例如,您要定义一个谓词#'weights-exactly-five-ounces-p吗?那#'weights-up-to-and-including-six-and-half-ounces-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)更少的写作,更少的阅读,没有额外的学习,琐碎的参数化。
例如,假设您想要一个水果列表,其颜色与您拥有的水果相同(在mine中),重量相同或可能更重……
(remove-if-not (lambda (x) (and (is-fruit-p x)
(eq (color x) (color mine))
(>= (weight x) (weight mine))))
objects)发布于 2013-03-19 05:39:52
quicklisp可安装的alexandria库中提供了诸如disjoin和conjoin之类的高阶函数。
CL-USER> (ql:quickload "alexandria")
...
CL-USER> (remove-if (alexandria:disjoin #'zerop #'oddp #'minusp)
'(0 -1 1 -2 2))
=> (2)https://stackoverflow.com/questions/15475769
复制相似问题