简体   繁体   English

在方案中追加反向清单

[英]Appending reversed list in Scheme

I am learning Scheme and wanted to write a recursive program that reverses a given list. 我正在学习Scheme,想编写一个递归程序来反转给定列表。

In one test case however, I noticed that a (bc) e -> e (bc) a . 但是,在一个测试案例中,我注意到a (bc) e > e (bc) a

What I'm trying to get is a (bc) e -> e (cb) a . 我想得到的是a (bc) e > e (cb) a

This is what I have: 这就是我所拥有的:

(define (deep-reverse lst)
(if (null? lst)
  '()
  (begin
    (display (car lst))
    (display "\n")
    (if (null? (cdr lst))
        '()
        (append (deep-reverse (cdr lst)) (list (reverse (car lst))))
        ) //End of inner if
))) //End of begin, outer if, define  

When I attempt to run the code with 当我尝试使用

(deep-reverse '(1 (bc) (ab))) (深度反转'(1(bc)(ab)))

I get: 我得到:

1
(b c)
(a b)
mcdr: contract violation
expected: mpair?
given: 1

The issue is with (list (reverse (car lst))) , although in an isolated test case it works fine. 问题是(list (reverse (car lst))) ,尽管在单独的测试用例中它可以正常工作。 Which leads me to believe that the issue may have to do with append. 这使我相信该问题可能与附加有关。

Thank you in advance. 先感谢您。

Edit: Going from (list (reverse (car lst))) to (reverse (list(car lst))) makes the code run without an error but doesn't reverse (ab) to (ba) . 编辑:(list (reverse (car lst)))(reverse (list(car lst)))使代码运行没有错误,但没有将(ab)反向为(ba)

As the error message explains, your problem is that you are trying to reverse a number. 正如错误消息所解释的那样,您的问题是您试图将数字取反。 Firstly, let's remove some of the unnecessary conditions and debugging stuff in your program, arriving at this simpler program. 首先,让我们删除一些不必要的条件并调试程序中的内容,以得到一个更简单的程序。 Let's step through this program to see what's going on: 让我们逐步看一下该程序,看看发生了什么:

(define (deep-reverse lst)
  (if (null? lst)
      '()
      (append (deep-reverse (cdr lst)) (list (reverse (car lst))))))

We start with 我们从

(deep-reverse '(1 (b c) (a b)))

Substituting the argument we get 代入我们得到的论点

(if (null? '(1 (b c) (a b)))
    '()
    (append (deep-reverse (cdr '(1 (b c) (a b))))
            (list (reverse (car '(1 (b c) (a b)))))))

Because the condition is #f , this simplifies to 由于条件是#f ,因此简化为

(append (deep-reverse (cdr '(1 (b c) (a b))))
                (list (reverse (car '(1 (b c) (a b))))))

To evaluate the first argument, first find the cdr , and call deep-reverse on that. 要评估第一个参数,请首先找到cdr ,然后在其上调用deep-reverse I will skip the steps here but you should easily be able to test that it works correctly. 我将在此处跳过这些步骤,但是您应该可以轻松测试它是否正常运行。

(append '((b a) (c b)) (list (reverse (car '(1 (b c) (a b))))))

Next we evaluate the car : 接下来,我们评估这car

(append '((b a) (c b)) (list (reverse 1)))

And here we see what the problem is: we can't reverse a single number! 在这里,我们看到了问题所在:我们不能取反单个数字!

The issue is that your deep-reverse should have two distinct behaviours recursively: 问题是您的deep-reverse应该递归地具有两种不同的行为:

  • on a number, or symbol, or other non-list entity, don't do anything, because it does not make sense to reverse a number 在数字,符号或其他非列表实体上,请勿执行任何操作,因为反转数字没有意义
  • on a list, deep reverse it 在列表上,将其深层反转

There are two reasons why your current program does not do this properly: 当前程序无法正确执行此操作有两个原因:

  • it only does a shallow reverse on the elements of the list; 它只对列表中的元素进行了轻微的反转; that is, it won't deep reverse '(((ab) (cd)) ((ef) (gh))) correctly 也就是说,它不会正确地深度反转'(((ab) (cd)) ((ef) (gh)))
  • it fails if it ever encounters a number or other non-list, like a symbol 如果遇到数字或其他非列表(例如符号),则失败

The easy fix is to add a condition to check if it's a pair? 简单的解决方法是添加条件以检查是否为一pair? first before attempting to reverse it. 首先尝试将其反转。 If it's not pair? 如果不是pair? , then lst must either be nil (which we may leave as-is) or a non-list object (which we may also leave as-is) ,则lst必须为nil (我们可以原样保留)或非列表对象(我们也可以原样保留)

(define (deep-reverse lst)
  (if (pair? lst)
      (append (deep-reverse (cdr lst)) (list (deep-reverse (car lst))))
      lst))

Finally, I should note that the pattern we are using here is really a foldr pattern. 最后,我应该指出,我们在这里使用的模式实际上是一个文件foldr模式。 We can abstract away this pattern with foldr : 我们可以用foldr来抽象掉这个模式

(define (deep-reverse xs)
  (cond ((pair? xs)
         (foldr (lambda (x y) (append y (list (deep-reverse x)))) '() xs))
        (else xs)))

But we note also that this is inefficient, because append is an expensive operation. 但是我们也注意到这是低效的,因为append是一项昂贵的操作。 Modifying the algorithm to a tail recursive one makes it clear that this is actually a foldl : 将算法修改为尾递归算法,可以清楚地看出这实际上是一个foldl

(define (deep-reverse xs)
  (cond ((pair? xs)
         (foldl (lambda (x y) (cons (deep-reverse x) y)) '() xs))
        (else xs)))

which is how such a function might be written in typical idiomatic Scheme, or as pointed out by Will Ness, 这样的功能可能是如何用典型的惯用方案编写的,或者如Will Ness所指出的那样,

(define (deep-reverse xs)
  (cond ((pair? xs) (reverse (map deep-reverse xs)))
        (else xs)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM