简体   繁体   English

方案:返回可以使用car和cdr的任意组合获得的表达式的所有元素

[英]Scheme: Return all elements of an expression that can be obtained using any combination of car and cdr

I'm trying to write a procedure in Scheme (R5RS) of my CS class that takes an expression (either a symbol or a list) as an argument and returns a list of (1) all the possible expression that can be formed by using car and cdr on the expression and (2) and an expression demonstrating how each of these components of the original expression were obtained. 我正在尝试在CS类的Scheme(R5RS)中编写一个过程,该过程将一个表达式(符号或列表)作为参数并返回(1)的所有可能表达式的列表,这些表达式可以通过使用car和cdr代表表达式(2)和一个表达式,说明如何获得原始表达式的这些组成部分。 If a piece can be obtained in more than one way, it should be returned more than once. 如果可以通过多种方式获得一件作品,则应将其退回不止一次。

Examples

(pieces '()) => ((() x))

(pieces 'apple) =>  ((apple x))

(pieces '(apple)) => (((apple) x) (apple (car x)) (() (cdr x)))

(pieces '(a (b c))) =>
               (((a (b c)) x)
                (a (car x))
                (((b c)) (cdr x))
                ((b c) (car (cdr x)))
                (b (car (car (cdr x))))
                ((c) (cdr (car (cdr x))))
                (c (car (cdr (car (cdr x)))))
                (() (cdr (cdr (car (cdr x)))))
                (() (cdr (cdr x))))

Since we've just started with Scheme, we're limited to fairly basic syntax for this assignment. 由于我们刚刚开始使用Scheme,因此仅限于此分配的相当基本的语法。 Here's what I have so far: 这是我到目前为止的内容:

(define pieces
  (lambda (exp)
    (cond
      ((symbol? exp)
       (list exp 'x))
      ((null? exp)
       (list '() 'x))
      ((list? exp)
       (let ((b (pieces (car exp))) (c (pieces (cdr exp))))
          (list exp 'x b c))))))

(pieces '()) => (() x)

(pieces 'apple) => (apple x)

(pieces '(apple)) => ((apple) x (apple x) (() x))

(pieces '(a (b c))) => ((a (b c)) x (a x) (((b c)) x ((b c) x (b x) ((c) x (c x) (() x)))
                       (() x)))

The procedure returns all of the proper elements, but each recursion causes the components to be nested in an additional list. 该过程返回所有适当的元素,但是每次递归都会使这些组件嵌套在其他列表中。 Is there any way to prevent that? 有什么办法可以防止这种情况?

Also, I have no idea where to start for the second part of the problem (showing how each element was obtained from the original using car and cdr). 另外,我不知道问题的第二部分从哪里开始(显示如何使用car和cdr从原始元素中获取每个元素)。 I've tried a million different approaches, and none of them have even been close to working. 我已经尝试了上百万种不同的方法,但是没有一个方法接近于可行。 If anyone has any hints or suggestions on how to implement that feature, I'd really appreciate it. 如果有人对如何实现该功能有任何提示或建议,我将非常感谢。 Thanks a ton. 万分感谢。

(pieces 'apple) => (apple x)

But it should be ((apple x)) , right? 但这应该是((apple x)) ,对吗? You should get a list where the first and only element is the list (apple x) . 您应该得到一个列表,其中第一个也是唯一的元素是列表(apple x)

The cond clauses that terminate recursion (exp is a symbol or null) return items that should go in the list, while the clause that recurs on car and cdr attempts to create a list of items. 终止递归的cond子句(exp是符号或null)将返回应包含在列表中的项目,而在carcdr上递归的子句则尝试创建项目列表。 As pieces can return both items and lists of items it's kind of hard to make a list of items out of the values that are returned from it: when you do (list exp 'xbc) you don't know if b and c are items that should go into the list or lists of items. 由于pieces既可以返回项目又可以返回项目列表,因此很难根据从其返回的值中列出项目:当您这样做(list exp 'xbc)您不知道bc是否为项目应该进入一个或多个项目列表。

If you make sure that pieces always returns a list of items (eg (list (list exp 'x)) ) it gets a lot easier. 如果您确保pieces始终返回项列表(例如(list (list exp 'x)) ),则变得容易得多。 When you recur on car and cdr you want to do something like append the lists a and b and add the "current" ( (list exp 'x) ) item to that list (maybe with cons or something). 当您再次使用carcdr您想要执行类似append列表ab然后将“当前”( (list exp 'x) )项添加到该列表中(可能包含cons或其他内容)。

For the second part, pieces must know how it got to the current item. 对于第二部分, pieces必须知道如何到达当前项目。 You can make pieces take a the "path" to the current item as a (maybe optional) parameter. 您可以使pieces采用到当前项目的“路径”作为(可能是可选的)参数。 If the path is a list, then when you call pieces on (car exp) you can add a car symbol to the path you're sending as argument, and for (cdr exp) you can add the symbol cdr . 如果路径是一个列表,那么当你调用pieces(car exp)你可以添加一个car象征你发送作为参数的路径,以及(cdr exp)可以添加符号cdr And then you use the path to create something nice to substitute for 'x in (list exp 'x) . 然后,使用该路径创建一些不错的东西来代替'x in (list exp 'x)

I know it's not Scheme, but maybe looking at similar language would help. 我知道这不是Scheme,但也许看看类似的语言会有所帮助。 I did this more to practice myself, so take it with a drip of salt, yet it seems to be doing exactly what you're after: 我做了更多这样的练习来练习自己,所以滴一滴盐就可以了,但它似乎完全可以满足您的要求:

(defun parse-list (whatever)
  (labels ((pieces (expression &optional path)
         (cond
           ((null expression)
        `((,path . nil)))
           ((listp expression)
        (append (list
             `(,path . ,expression))
            (pieces (car expression)
                (cons 'car path))
            (pieces (cdr expression)
                (cons 'cdr path))))
           (t `((,path . ,expression))))))
    (dolist (output (pieces whatever))
      (format t "path ~a => result ~a~&"
          (car output) (cdr output)))))

(parse-list '(a (b c)))

Which then produces this output: 然后产生以下输出:

path NIL => result (A (B C))
path (CAR) => result A
path (CDR) => result ((B C))
path (CAR CDR) => result (B C)
path (CAR CAR CDR) => result B
path (CDR CAR CDR) => result (C)
path (CAR CDR CAR CDR) => result C
path (CDR CDR CAR CDR) => result NIL
path (CDR CDR) => result NIL

Sorry, I couldn't get SO's code formatting better than this :) 抱歉,我无法获得比这更好的SO的代码格式:)

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

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