如何在此处反转谓词?
我有以下过滤程序:
; (2) filter
(define (filter test sequence)
; return a list of the elements that pass the predicate test
(let ((elem (if (null? sequence) nil (car sequence)))
(rest (if (null? sequence) nil (cdr sequence))))
(cond ((null? sequence) nil)
((test elem) (cons elem (filter test rest)))
(else (filter test rest)))))
下面是一个使用它返回列表的偶数元素的示例:
(define even? (lambda (x) (= (modulo x 2) 0)))
(define sequence '(1 2 3 4 5 8 9 11 13 14 15 16 17))
(filter even? sequence)
; (2 4 8 14 16)
有没有一种简单的方法可以使用not测试来反转选择?例如,我认为以下可能有效:
(filter (not even?) sequence)
但它返回一个错误。我odd当然可以单独定义:
(define odd? (lambda (x) (not (even? x))))
但我尽量不这样做。有没有办法编写odd程序而不直接定义它,而是not像我上面尝试做的那样直接使用?
回答
complementCommon Lisp 中有一个函数可以完成我认为您正在寻找的功能。complement是一个以过程为参数的高阶过程,并返回一个与输入过程采用相同参数并执行相同动作的过程,但返回的真值相反。
Racket 有一个类似的过程,negate在 Scheme 中很容易实现:
(define (complement f)
(lambda xs (not (apply f xs))))
> (filter even? '(1 2 3 4 5))
(2 4)
> (filter (complement even?) '(1 2 3 4 5))
(1 3 5)
> (> 1 2 3 4 5)
#f
> ((complement >) 1 2 3 4 5)
#t
在球拍中:
scratch.rkt> (filter even? '(1 2 3 4 5))
'(2 4)
scratch.rkt> (filter (negate even?) '(1 2 3 4 5))
'(1 3 5)
scratch.rkt> (> 1 2 3 4 5)
#f
scratch.rkt> ((negate >) 1 2 3 4 5)
#t