如何在此处反转谓词?

Dav*_*542 3 lisp scheme predicate function-composition racket

我有以下过滤程序:

; (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)))))
Run Code Online (Sandbox Code Playgroud)

下面是一个使用它返回列表的偶数元素的示例:

(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)
Run Code Online (Sandbox Code Playgroud)

有没有一种简单的方法可以使用not测试来反转选择?例如,我认为以下可能有效:

(filter (not even?) sequence)
Run Code Online (Sandbox Code Playgroud)

但它返回一个错误。我odd当然可以单独定义:

(define odd?  (lambda (x) (not (even? x))))
Run Code Online (Sandbox Code Playgroud)

但我尽量不这样做。有没有办法编写odd程序而不直接定义它,而是not像我上面尝试做的那样直接使用?

ex *_*ilo 5

complementCommon Lisp 中有一个函数可以完成我认为您正在寻找的功能。complement是一个以过程为参数的高阶过程,并返回一个与输入过程采用相同参数并执行相同动作的过程,但返回的真值相反。

Racket 有一个类似的过程,negate在 Scheme 中很容易实现:

(define (complement f)
  (lambda xs (not (apply f xs))))
Run Code Online (Sandbox Code Playgroud)
> (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
Run Code Online (Sandbox Code Playgroud)

在球拍中:

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
Run Code Online (Sandbox Code Playgroud)