将s表达式转换为Scheme中的列表

时间:2013-05-09 02:44:03

标签: lisp scheme racket

如果我有一个s表达式,例如'(1 2(3)(4(5))6 7),我如何将其转换为像(1 2 3 4 5 6 7)这样的列表?我基本上需要从s表达式中提取所有原子。是否有内置功能可以帮助我做到这一点?

(define (convert-to-list s) ... )

到目前为止,我的算法是,如果第一个元素是原子,则将其附加到列表中。如果第一个元素是一个列表,那么获取该元素的汽车,然后使用该函数调用该函数(convert-to-list),以便捕获递归的基本情况。并将转换为列表时调用的该列表的cdr附加到它的car。我正在尝试从计算机程序的结构和解释中自学计划,我只是尝试随机的东西。递归地做这件事证明比我预期的要困难得多。

5 个答案:

答案 0 :(得分:4)

字面上回答你的问题,“是否有内置功能可以帮助我这样做?”,在Racket中是的。 flatten正是如此:“将对的任意S表达式结构展平为列表。”

Examples:
> (flatten '((a) b (c (d) . e) ()))
'(a b c d e)
> (flatten 'a)
'(a)

然而,考虑一下如何自己写flatten是一个很好的练习。

Chris Jester-Young的评论链接到一种优雅的方式。如果她将其作为答案发布,而不是作为评论,我建议将她的答案标记为已接受,而不是我的。 :)

答案 1 :(得分:1)

你的算法看起来不错,只是错过了一两步。

(define (flatten lst) ; 'flatten' is a better name for this function IMO
  (cond
    ((null lst) nil)
    ;; Don't worry that I'm calling (flatten (cdr lst)) without any checking;
    ;;  the above case handles it
    ((atom (car lst)) ; The car's okay
     (cons (car lst) (flatten (cdr lst))))
    ((cons? (car lst)) ; The car still needs flattening; note the use of
                       ;  'append' here (the car-list may have any number of elements)
     (append (flatten (car lst)) (flatten (cdr lst))))))

在处理第一个元素的(flatten (car lst))调用和递归处理列表其余部分的(flatten (cdr lst))调用之间,输入列表最终得到一个平面列表(即没有元素是conses)。 / p>

警告:我不是Scheme大师;上面的代码可能包含错误。)

答案 2 :(得分:1)

你的案件应该包括空列表,原子,(汽车)是一个原子,(汽车)是一个列表。

这很有效,虽然我打破了一个列表附加功能,因为我不记得内置功能。适用于球拍高级学生。

(define (list-glue left-list right-list)
  (cond
    ((null? left-list) right-list)
    (else (cons (car left-list) (list-glue (cdr left-list) (right-list))))))

(define (convert-to-list s)
  (cond 
    ((null? s) '())
    ((not (list? s)) (cons s (quote ())))
    ((not (list? (car s))) (cons (car s) (convert-to-list (cdr s))))
    (else 
      (list-glue 
        (convert-to-list (car s))
        (convert-to-list (cdr s))))))

答案 3 :(得分:1)

现在,如果您想要更快的实施,则根本不需要append

这个想法是传递你要附加的参数。我叫这个尾巴。 如果你有一个空的s-exp,你只需返回尾部,因为没有任何内容可以添加。

我有代码flatflat2,其中flat使用match语句,球拍中的内容,flat2只使用了cond,我觉得有点难以阅读,但如果您还没有看到match,我会提供它。

#lang racket


(define (flat s-exp tail)
  (match s-exp
         ['() tail]
         [(cons fst rst)
          (let ([new-tail (flat rst tail)])
            (flat fst new-tail))]
         [atom
          (cons atom tail)]))

(define (flat
  (cond
    [(empty? s-exp) tail]
    [(list? s-exp)
     (let* ([fst (first s-exp)]
            [rst (rest  s-exp)]
            [new-tail (flat])
       (flat fst new-tail))]
    [#t 
     (cons s-exp tail)]))

要使用它们,请将其称为(flat '(1 () (2 (3)) 4) '()) ===> '(1 2 3 4)。 你需要为它们提供空列表。

答案 4 :(得分:0)

这可以通过递归子列表和休息列表来完成。您可以看到此代码读取的容易程度。像这样:

(define (convert-to-list list)
  (if (null? list)
      '()
      (let ((next (car list))
            (rest (cdr list)))
        (if (list? next)
            (append (convert-to-list next) (convert-to-list rest))
            (cons next (convert-to-list rest))))))
> (convert-to-list '(a b c))
(a b c)
> (convert-to-list '((a b) (((c d) e f) g h) i j))
(a b c d e f g h i j)
>