Scheme 一次展平程序

Scheme 一次展平程序,scheme,lisp,racket,Scheme,Lisp,Racket,我在编写一个将列表展平一次的过程时遇到了一些困难,即 (展平一次’((b)(cf)(d)(e))将产生(bcf(d)(e))。我查阅了一些关于标准展平过程工作原理的资料,但它实现了我必须使用的中级学生lambda语言表单中未包含的功能。据我所知,一个foldr会有所帮助,并且已经成功地做到了这一点 (define (flatten-once lst) (cond [(empty? lst) lst] [else ((foldr cons (first (rest lst

我在编写一个将列表展平一次的过程时遇到了一些困难,即
(展平一次’((b)(cf)(d)(e))
将产生
(bcf(d)(e))
。我查阅了一些关于标准展平过程工作原理的资料,但它实现了我必须使用的
中级学生lambda
语言表单中未包含的功能。据我所知,一个
foldr
会有所帮助,并且已经成功地做到了这一点

(define (flatten-once lst)
  (cond
   [(empty? lst) lst]
   [else 
    ((foldr cons (first (rest lst)) (first lst)))]))

它返回
”(bcf)
,所以我猜它会使列表的一部分变平。我尝试通过递归继续定义,但这只会产生错误,所以我想我遗漏了一些东西。

建议的代码过于复杂,请抵制到处使用折叠的诱惑,它们不是所有问题的答案-我这么说是因为我经常看到您的其他问题,对
foldr
foldl
有一个不必要的调用。一个简单的
append
就可以做到:

(define (flatten-once lst)
  (apply append lst))
它按预期工作:

(flatten-once '((b) (c f) ((d)(e))))
=> '(b c f (d) (e))
如果输入列表包含非列表的元素,则需要做更多的工作。要特别小心,我们可以这样做:

(define (flatten-once lst)
  (apply append
         (map (lambda (e) (if (cons? e) e (list e)))
              lst)))
现在,它将适用于这样的输入,注意元素
a
已添加到列表中。另一种选择是将其从列表中删除,如果这更有意义,则将上述代码中的
(列表e)
替换为
”()

(flatten-once '(a (b) (c f) ((d)(e))))
=> '(a b c f (d) (e))
最后,根据@Alex回答的精神,第二个变体也可以使用
foldr
编写:

(define (flatten-once lst)
  (foldr (lambda (e acc)
           (append (if (cons? e) e (list e)) acc))
         '()
         lst))

建议的代码过于复杂,请抵制到处使用折叠的诱惑,它们不是所有问题的答案-我这样说是因为我看到了您的其他问题,而且经常会有不必要的调用
foldr
foldl
。一个简单的
append
就可以做到:

(define (flatten-once lst)
  (apply append lst))
它按预期工作:

(flatten-once '((b) (c f) ((d)(e))))
=> '(b c f (d) (e))
如果输入列表包含非列表的元素,则需要做更多的工作。要特别小心,我们可以这样做:

(define (flatten-once lst)
  (apply append
         (map (lambda (e) (if (cons? e) e (list e)))
              lst)))
现在,它将适用于这样的输入,注意元素
a
已添加到列表中。另一种选择是将其从列表中删除,如果这更有意义,则将上述代码中的
(列表e)
替换为
”()

(flatten-once '(a (b) (c f) ((d)(e))))
=> '(a b c f (d) (e))
最后,根据@Alex回答的精神,第二个变体也可以使用
foldr
编写:

(define (flatten-once lst)
  (foldr (lambda (e acc)
           (append (if (cons? e) e (list e)) acc))
         '()
         lst))

正如奥斯卡·洛佩斯(Oscar López)已经说过的,诀窍是使用
附加

如果要将解决方案与
foldr
一起使用:

(define (flatten-once lst)
  (foldr append '() lst))

它应该像预期的那样工作。

诀窍正如奥斯卡·洛佩斯所说的,使用
附加

如果要将解决方案与
foldr
一起使用:

(define (flatten-once lst)
  (foldr append '() lst))

它应该可以像预期的那样工作。

没有奥斯卡版本那么优雅,但是没有添加
附件(在我的测试中速度是后者的两倍):

NB在使用lambda语言的中级学生中
这需要表示为:

(define (flatten-once-helper lst first res)
  (if (null? lst)
      res
      (let ((e (car lst)))
        (flatten-once-helper 
         (cdr lst) 
         first
         (if (and first (cons? e))
             (flatten-once-helper e #f res)
             (cons e res))))))

(define (flatten-once lst)  
  (reverse (flatten-once-helper lst #t null)))

没有奥斯卡的版本那么优雅,但是没有添加
附加
(在我的测试中速度是奥斯卡的两倍):

NB在使用lambda语言的中级学生中
这需要表示为:

(define (flatten-once-helper lst first res)
  (if (null? lst)
      res
      (let ((e (car lst)))
        (flatten-once-helper 
         (cdr lst) 
         first
         (if (and first (cons? e))
             (flatten-once-helper e #f res)
             (cons e res))))))

(define (flatten-once lst)  
  (reverse (flatten-once-helper lst #t null)))

那么
(展平一次(a(b)(c f)((d)(e)))
?@uselpa不知道输入是否可以包含非列表,但为了安全起见,我更新了我的答案。谢谢你指出这一点<代码>配对?
未在
中级学生中定义,且具有lambda
无需复制
(列表e)
具有
附加
;折叠功能可以等效为
(lambda(e acc)(if(cons?e)(append e acc)(cons e acc))
@JoshuaTaylor无需。你不能附加非列表,所以如果存在非列表,它应该会失败,IMHO。那么
(展平一次)(a(b)(c f)((d)(e)))
?@uselpa输入是否可以包含非列表是未知的,但为了安全起见,我更新了我的答案。谢谢你指出这一点<代码>配对?
未在
中级学生中定义,且具有lambda
无需复制
(列表e)
具有
附加
;折叠功能可以等效为
(lambda(e acc)(if(cons?e)(append e acc)(cons e acc))
@JoshuaTaylor无需。你不能附加一个非列表,所以如果存在非列表,它应该会失败,IMHO。虽然它对于你的学校作业和中级学生语言是N/a,但在“真实的”Racket中“展平一级”是。虽然对于你的学校作业和中级学生语言是N/a,但是在“真实的”Racket中“展平一级”是。那么
(展平一次’(a(b)(cf)((d)(e)))
?@uselpa另一个地方,如果Scheme/Racket的
fold[lr]
函数像Common Lisp的
reduce那样使用
参数,那会更好;它应该是
(reduce'append lst:key'到列表中)
:\@JoshuaTaylor列表的
是什么?这里值得注意的是,使用正确的关联折叠非常重要。对于列表
(wxyz)
,它相当于
(追加w(追加x(追加y(追加z’(!))))
,只复制足够的长度(结果的长度)并且应该以线性时间运行。左关联折叠应该是
(append(append(append(append w’())x)y)z)
和将分配大量额外内存,并以二次时间运行。@uselpa有没有比
append
更快的方法来获取两个列表
x
y
,并创建一个以
x
元素开始并以
y
作为尾部的新列表?除非OP希望以破坏性方式执行此操作,否则所有这些在顶级列表旁边需要复制(除了最后一个),这正是
append
所做的。那么
(展平一次(a(b)(cf)((d)(e))
?@uselpa另一个地方,如果Scheme/Racket的
fold[lr]
函数像Com一样使用
参数会更好吗