List Scheme/Racket:一个函数,它将一个列表分成两个元素列表,一个匹配某个谓词,另一个不匹配';不匹配

List Scheme/Racket:一个函数,它将一个列表分成两个元素列表,一个匹配某个谓词,另一个不匹配';不匹配,list,scheme,lisp,racket,predicate,List,Scheme,Lisp,Racket,Predicate,我希望在Scheme中创建一个函数,该函数接受谓词和元素列表,然后输出两个单独的列表。一个是原始列表中与给定谓词匹配的元素,另一个是与给定谓词不匹配的元素 我认为我现在的代码应该隔离那些与谓词匹配的代码,并输出它们的列表,但代码不会工作 (define tear (lambda (pred xs) (cond[(null? xs) '()] [(list? (car xs))(cons((tear (pred (car xs)))(tear (pred (cdr

我希望在Scheme中创建一个函数,该函数接受谓词和元素列表,然后输出两个单独的列表。一个是原始列表中与给定谓词匹配的元素,另一个是与给定谓词不匹配的元素

我认为我现在的代码应该隔离那些与谓词匹配的代码,并输出它们的列表,但代码不会工作

    (define tear
(lambda (pred xs)
    (cond[(null? xs) '()]
         [(list? (car xs))(cons((tear (pred (car xs)))(tear (pred (cdr xs)))))]
         [(pred (car xs))(cons((car xs)(tear (pred (cdr xs)))))]
         [else tear (pred (cdr xs))])))
(tear number? '(1 2 3 a b c))
我的编译器上的结果输出为:

    tear: arity mismatch;
 the expected number of arguments does not match the given number
  expected: 2
  given: 1
  arguments...:
   #f
  context...:
   /home/jdoodle.rkt:2:4: tear
Command exited with non-zero status 1

非常感谢您提供的任何帮助/信息。

让我们逐步修复您的代码。添加缩进和空白以使其可读:

(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       '()]
      [(list? (car xs))
       (cons ((tear (pred (car xs))) (tear (pred (cdr xs)))))]
      [(pred (car xs))
       (cons ((car xs) (tear (pred (cdr xs)))))]
      [else 
       tear (pred (cdr xs))])))

(tear number? '(1 2 3 a b c))
我看到的第一个问题是将括号放在函数调用的内部(围绕参数),而不是外部。您可以使用
cons
和对
tear
的递归调用来执行此操作。例如,在
tear(pred(cdr-xs))
中,您应该将第一个paren移动到函数之前。请记住,表达式中的括号几乎总是表示形式为
(函数参数…
)的函数调用

  • (cons(ab))
    应重写为
    (cons A B)
  • (撕裂(Pred-Xs))
    应重写为
    (撕裂Pred-Xs)
  • 撕裂(Pred-Xs)
    应重写为
    (撕裂Pred-Xs)
通过这些修复,您的代码如下所示:

(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       '()]
      [(list? (car xs))
       (cons (tear pred (car xs)) (tear pred (cdr xs)))]
      [(pred (car xs))
       (cons (car xs) (tear pred (cdr xs)))]
      [else 
       (tear pred (cdr xs))])))

(tear number? '(1 2 3 a b c))
;=> (1 2 3)
(tear number? '(1 2 "not a number" 3 4))
;=> (1 2 3 4)
但是,当存在嵌套列表时,它仍然会做一些奇怪的事情:

(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=error> (() ())
为了保持一致,它应该将两个列表放入一个列表中:
((1 2 3)(4 5))
。为此,只需删除第二个
cond
案例:

(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       '()]
      [(pred (car xs))
       (cons (car xs) (tear pred (cdr xs)))]
      [else 
       (tear pred (cdr xs))])))

(tear number? '(1 2 3 a b c))
;=> (1 2 3)
(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=> ((1 2 3) (4 5))
现在它似乎只做了你想要的一半。您希望它返回两个列表:一个用于通过的元素,另一个用于失败的元素。它目前只返回第一个列表

您应该做的第一件事是记录它如何返回这两个列表。因为总是正好有两个,所以可以将它们作为多个值返回

;; tear returns two values:
;;  - a list of the elements of `xs` that passed `pred`
;;  - a list of the elements of `xs` that failed `pred`
使用多个值有两个部分:返回和接收。使用
(值ab)
返回它们,并使用
(让值([(ab)…])
匹配结果,如递归调用的结果

这意味着像这样的每个递归调用都应该

(let-values ([(A B) (tear ....)])
  (values (f .... A ....)
          ???))
将其应用于代码:

;; tear returns two values:
;;  - a list of the elements of `xs` that passed `pred`
;;  - a list of the elements of `xs` that failed `pred`
(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       (values '()
               ???)]
      [(pred (car xs))
       (let-values ([(A B) (tear pred (cdr xs))])
         (values (cons (car xs) A)
                 ???))]
      [else
       (let-values ([(A B) (tear pred (cdr xs))])
         (values A
                 ???))])))
现在,使用示例来填充

  • (撕裂编号?')
    应返回两个空列表:
    ()
  • (撕裂编号?'(12))
    应返回完整列表和空列表:
    (12)(
  • (撕裂编号?'(a b))
    应返回空列表和完整列表:
    ()(a b)
第一个示例对应于第一个
孔,第二个示例对应于第二个孔,依此类推

这告诉我们第一个孔应该用
'()
填充,第二个孔应该用
B
填充,第三个孔应该用
(cons(car xs)B)
填充


让我们一步一步地修复代码。添加缩进和空白以使其可读:

(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       '()]
      [(list? (car xs))
       (cons ((tear (pred (car xs))) (tear (pred (cdr xs)))))]
      [(pred (car xs))
       (cons ((car xs) (tear (pred (cdr xs)))))]
      [else 
       tear (pred (cdr xs))])))

(tear number? '(1 2 3 a b c))
我看到的第一个问题是将括号放在函数调用的内部(围绕参数),而不是外部。您可以使用
cons
和对
tear
的递归调用来执行此操作。例如,在
tear(pred(cdr-xs))
中,您应该将第一个paren移动到函数之前。请记住,表达式中的括号几乎总是表示形式为
(函数参数…
)的函数调用

  • (cons(ab))
    应重写为
    (cons A B)
  • (撕裂(Pred-Xs))
    应重写为
    (撕裂Pred-Xs)
  • 撕裂(Pred-Xs)
    应重写为
    (撕裂Pred-Xs)
通过这些修复,您的代码如下所示:

(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       '()]
      [(list? (car xs))
       (cons (tear pred (car xs)) (tear pred (cdr xs)))]
      [(pred (car xs))
       (cons (car xs) (tear pred (cdr xs)))]
      [else 
       (tear pred (cdr xs))])))

(tear number? '(1 2 3 a b c))
;=> (1 2 3)
(tear number? '(1 2 "not a number" 3 4))
;=> (1 2 3 4)
但是,当存在嵌套列表时,它仍然会做一些奇怪的事情:

(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=error> (() ())
为了保持一致,它应该将两个列表放入一个列表中:
((1 2 3)(4 5))
。为此,只需删除第二个
cond
案例:

(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       '()]
      [(pred (car xs))
       (cons (car xs) (tear pred (cdr xs)))]
      [else 
       (tear pred (cdr xs))])))

(tear number? '(1 2 3 a b c))
;=> (1 2 3)
(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=> ((1 2 3) (4 5))
现在它似乎只做了你想要的一半。您希望它返回两个列表:一个用于通过的元素,另一个用于失败的元素。它目前只返回第一个列表

您应该做的第一件事是记录它如何返回这两个列表。因为总是正好有两个,所以可以将它们作为多个值返回

;; tear returns two values:
;;  - a list of the elements of `xs` that passed `pred`
;;  - a list of the elements of `xs` that failed `pred`
使用多个值有两个部分:返回和接收。使用
(值ab)
返回它们,并使用
(让值([(ab)…])
匹配结果,如递归调用的结果

这意味着像这样的每个递归调用都应该

(let-values ([(A B) (tear ....)])
  (values (f .... A ....)
          ???))
将其应用于代码:

;; tear returns two values:
;;  - a list of the elements of `xs` that passed `pred`
;;  - a list of the elements of `xs` that failed `pred`
(define tear
  (lambda (pred xs)
    (cond
      [(null? xs) 
       (values '()
               ???)]
      [(pred (car xs))
       (let-values ([(A B) (tear pred (cdr xs))])
         (values (cons (car xs) A)
                 ???))]
      [else
       (let-values ([(A B) (tear pred (cdr xs))])
         (values A
                 ???))])))
现在,使用示例来填充

  • (撕裂编号?')
    应返回两个空列表:
    ()
  • (撕裂编号?'(12))
    应返回完整列表和空列表:
    (12)(
  • (撕裂编号?'(a b))
    应返回空列表和完整列表:
    ()(a b)
第一个示例对应于第一个
孔,第二个示例对应于第二个孔,依此类推

这告诉我们第一个孔应该用
'()
填充,第二个孔应该用
B
填充,第三个孔应该用
(cons(car xs)B)
填充


这里有另一种方法,你可以使用;这就引入了递归调用

上面,我们利用了球拍的优势。下面我们将展示如何定义
partit