Scheme 这里如何反转谓词?

Scheme 这里如何反转谓词?,scheme,lisp,racket,predicate,function-composition,Scheme,Lisp,Racket,Predicate,Function Composition,我有以下过滤程序: ; (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? se

我有以下过滤程序:

; (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))))
(define odd? (compose-1 not even)

但我尽量不这么做。有没有一种方法可以编写
odd
过程而不直接定义它,而是直接使用
not
,就像我在上面尝试做的那样?

一个选项是编写一个
invert
函数,它将继续执行(因此初始函数仍然接受一个参数),直到最终求值:

(define invert (lambda (func) (lambda (x) (not (func x)))))
(define sequence '(1 2 3 4 5 6 8 9 11 13 14 15 16 17))
(filter (invert even?) sequence)
; (1 3 5 9 11 13 15 17)
在CommonLisp中有一个函数,可以实现我认为您需要的功能<代码>补码是一个高阶过程,它将一个过程作为其参数,并返回一个过程,该过程采用与输入过程相同的参数并执行相同的操作,但返回的真值是反转的

Racket有一个类似的程序,在方案中很容易实现:

(定义(补码f)
(lambda xs(不适用于f xs)))
>(过滤偶数?'(1 2 3 4 5))
(2 4)
>(过滤器(补码偶数?)(1 2 3 4 5)
(1 3 5)
> (> 1 2 3 4 5)
#f
>((补语>)1 2 3 4 5)
#t
在球拍中:

scratch.rkt>(过滤偶数?'(1 2 3 4 5))
'(2 4)
scratch.rkt>(过滤器(是否为偶数?)(1 2 3 4 5)
'(1 3 5)
scratch.rkt>(>12345)
#f
scratch.rkt>((否定>)1 2 3 4 5)
#t

一般的答案是简单地编写
而不是
和您关心的函数。Racket有一个
compose
函数,可以实现这一点,但您可以自己轻松编写一个简单的函数:

(define (compose-1 . functions)
  ;; simple-minded compose: each function other than the last must
  ;; take just one argument; all functions should return just one
  ;; value.
  (define (compose-loop fns)
    (cond
      ((null? fns)
       (λ (x) x))
      ((null? (cdr fns))
       (car fns))
      (else
       (λ (x) ((car fns) ((compose-loop (cdr fns)) x))))))
  (compose-loop functions))
当然,要使它更高效、更通用,需要做更多的工作

然后您可以定义
奇数?
(当然已经定义):

或者实际上定义一个更通用的CL样式
补码
函数:

(define (complement f)
  (compose-1 not f))

谢谢,出于好奇,与我在上面的答案中所写的功能相比,您拥有的功能有什么优势?最主要的是它会执行所有的空检查,或者什么是你的工作但我的失败的例子?@David542:my
compose-1
会组成任何单参数单值函数:
(compose-1zero?(lambda(x)(+x1))
,比方说,它会返回一个函数,告诉你它的参数是否为-1(好的,有更简单的方法可以做到这一点。)
invert
这个定义的一个缺点是它只适用于一元过程。也就是说,这将适用于
偶数?
,但它不起作用,例如,对于
。我在回答中展示了这个例子:
((否定>)1 2 3 4 5)
-->
#t
,但
((反向)1 2 3 4 5)
-->算术不匹配。CL
complete
、Racket
negate
,以及我展示的
complete
的方案定义都可以在n元过程中操作。@adabsurdum啊,好的,谢谢你指出这一切!我感觉到了你的痛苦,但你真的必须使用类似于方案的方案。
nil
不是列表中的空列表Scheme.When
(null?sequence)
为true时,您希望返回
()
。不,您也不能得到它,因为它不是自评估的;您必须引用它:
()
。从列表中删除匹配项或不匹配项是非常常见的操作。我将避免强迫程序员编写笨拙的否定,只需提供
keep if
remove if
功能。