我在Scheme中做了一个问题,就是创建一个函数,它接受一个对象和一个表达式,例如(foo 'x '(x 10 x x 4))
,并且必须返回跟随给定对象的所有对象,所以上面的函数调用会返回(10 x 4)
。但是,该表达式还可以包含列表,例如(foo 'y '(y (3 y 5 y y 8 9) (10 y 12 13 y 15 y) 17))
应返回((3 y 5 y y 8 9) 5 y 8 12 15)
。当它们包含列表时我遇到了麻烦。到目前为止,这是我的代码。
(define (foo target expression)
(cond [(null? expression)]
[(list? (first expression)) (foo target (first expression))]
[(eqv? (first expression) target) (cons (first (rest expression)) (foo target (rest expression)))]
[(not (eqv? (first expression) target)) (foo target (rest expression))]))
因此,当表达式包含列表时,我试图以递归方式调用该列表上的函数,但是,我不知道如何返回原始表达式继续搜索。
所以,当我打电话给(foo 'y '(y (3 y 5 y y 8 9) (10 y 12 13 y 15 y) 17))
时,我得到了((3 y 5 y y 8 9) 5 y 8 . #t)
,所以它成功地遍历第一个列表,但是在此之后它停止并且没有到达表达式中的第二个列表
另外,我遇到的另一个问题是我的结果中的布尔值,我知道这是因为行cond [(null? expression)]
,我添加了这个,因为当它到达结束时我收到了一个错误表达式,我该如何解决这个问题?
答案 0 :(得分:1)
请注意,(cons x (cons y ...
只有在使用空列表'()
终止时才会成为正确的列表。因此(cons x (cons y ... empty))
是正确的,相当于(list x y ...)
,而不是你拥有的(cons x (cons y ... #t))
。'()
。您可以通过将(first (rest expression))
作为基本案例的结果来解决此问题。
但是你还需要第二个基本案例来测试输入列表何时少于2个元素。这是因为您的函数稍后尝试以expression
的形式访问第二个元素。因此,为了确保这是有效的,您需要确保... (null? (rest expression)) ...
至少包含2个元素。这可以在您的cond案例中以[(list? (first expression)) (foo target (first expression))]
完成。
另一方面,你的函数只迭代它遇到的第一个列表元素,因为这行:
(first expression)
在这种情况下,您只需处理(first expression)
,但您需要同时处理(rest expression)
和(cons (foo target (first expression))
(foo target (rest expression)))
。由于您正在重建列表,因此可以使用cons as:
append
但这会重新创建原始列表的深度。从您想要的输出示例中,您似乎想要展平结果,因此更好的选择是(append (foo target (first expression))
(foo target (rest expression)))
将它们作为:
(define (foo obj expr)
(cond
[(null? expr) #f]
[(null? (rest expr)) '()]
[(pair? (first expr))
(append (foo obj (first expr))
(foo obj (rest expr)))]
[(equal? obj (first expr))
(cons (second expr)
(foo obj (rest expr)))]
[else
(foo obj (rest expr))]))
考虑以下重写:
(foo 'x '(x 10 x x 4))
=> '(10 x 4)
(foo 'y '(y (3 y 5 y y 8 9) (10 y 12 13 y 15 y) 17))
=> '((3 y 5 y y 8 9) 5 y 8 12 15)
然后你会:
(foo 'x '())
=> #f
(foo 'x '(x))
=> '()
但你也会:
{{1}}