Scheme 如何使用列表中的元素构造特定形状的树

Scheme 如何使用列表中的元素构造特定形状的树,scheme,Scheme,给定一个s表达式”((a.b.)(c.d))和一个列表”(e f g h),我如何遍历s表达式创建一个形状相同但元素取自列表的s表达式?例如,对于上面的s表达式和列表,结果将是”((E.f)g.h)?我假设您希望创建一个新的s表达式,其形状与第一个参数给定的s表达式的形状相同,但第二个参数中的列表元素相同 如果这是正确的,这里有一个可能的解决方案,使用列表来保存我们在替换列表中的位置,并使用Racket来更新列表(如果您的口译员没有更新列表,请使用让,正如Chris和Joshua在评论中建议的那

给定一个s表达式
”((a.b.)(c.d))
和一个列表
”(e f g h)
,我如何遍历s表达式创建一个形状相同但元素取自列表的s表达式?例如,对于上面的s表达式和列表,结果将是
”((E.f)g.h)

我假设您希望创建一个新的s表达式,其形状与第一个参数给定的s表达式的形状相同,但第二个参数中的列表元素相同

如果这是正确的,这里有一个可能的解决方案,使用列表来保存我们在替换列表中的位置,并使用Racket来更新列表(如果您的口译员没有更新列表,请使用
,正如Chris和Joshua在评论中建议的那样):

例如:

(transform '((a . b) . (c . d)) '(e f g h))
=> '((e . f) g . h)

(transform '((a . b) (c d (x y) . z) . t) '(e f g h i j k m))
=> '((e . f) (g h (i j) . k) . m)

该解决方案类似于我的:

然后


按从左到右的顺序遍历成对树并不特别困难,因为carcdr可以让你到达两边,而cons可以把东西重新组合起来。像这样的问题中棘手的部分是,要“替换”树右侧的元素,您需要知道在处理树左侧时使用了多少可用输入。因此,这里有一个过程重塑,它接受一个模板(一个具有所需形状的树)和一个元素列表以在新树中使用。它以多个值的形式返回新树和列表中的任何剩余元素。这意味着在对pair的递归调用中,您可以轻松地获得新的左子树和右子树以及其余元素

(define (reshape template list)
  ;; Creates a tree shaped like TEMPLATE, but with 
  ;; elements taken from LIST.  Returns two values: 
  ;; the new tree, and a list of any remaining
  ;; elements from LIST.
  (if (not (pair? template))
      (values (first list) (rest list))
      (let-values (((left list) (reshape (car template) list)))
        (let-values (((right list) (reshape (cdr template) list)))
          (values (cons left right) list)))))


即使我发现
set的用法总的来说令人厌恶,我目前没有更好的解决方案。不过,最好不要使用
list ref
。您可以执行类似于
(let((result(carlst)))(set!lst(cdrlst))result)的操作。(一般来说,Common Lisp有一个
prog1
宏来处理这类事情,不过在这种特殊情况下,它的
pop
宏更直接。)@ChrisJester-Young我认为简单地让函数返回多个值(新树和输入列表中的其余元素)会更优雅一些。然后从递归调用中获得继续所需的所有信息。我用这种方法添加了一个答案。即使在这种状态可变的方法中,为什么要使用列表引用和索引?不会更新lst(即,
(set!lst(rest-lst))
更简单吗?那么结果的元素总是在lst前面可用。好了,伙计们,我更新了我的答案。当然,
list ref
是一个深夜黑客:P。我们不知道OP的解释器中是否有
begin0
,如果没有,我们可以按照建议使用
let
。我喜欢
重塑
temp晚些时候
,它们是更好的名称,但请避免使用
列表
作为参数名称。另外值得一提的是,
let values
可能在某些解释器中不可用。此外,这不适用于所有输入,例如,使用我答案中的第二个示例进行测试。此方法非常有效,但是否可以仅重新设置打开新的树?@Jacob使用
让值
捕获结果并返回第一个值。但要注意,这并不适用于所有输入,例如,尝试以下操作:
(重塑’(ab)’(cd))
@scarLópez列表
(ab)
就是树
(ab.))有三种东西需要替换,而不是两种,所以<代码>(Cd)是不够的元素。我认为既然问题需要在S表达式中替代,而不是列表,那么考虑树而不是列表是合适的。
(define (transform sxp lst)
  (let loop ((sxp sxp))
    (cond ((null? sxp) sxp)
          ((pair? sxp) (cons (loop (car sxp)) (loop (cdr sxp))))
          (else (begin0 (car lst) (set! lst (cdr lst)))))))
> (transform '((a . b) . (c . d)) '(e f g h))
'((e . f) g . h)
(define (reshape template list)
  ;; Creates a tree shaped like TEMPLATE, but with 
  ;; elements taken from LIST.  Returns two values: 
  ;; the new tree, and a list of any remaining
  ;; elements from LIST.
  (if (not (pair? template))
      (values (first list) (rest list))
      (let-values (((left list) (reshape (car template) list)))
        (let-values (((right list) (reshape (cdr template) list)))
          (values (cons left right) list)))))
(reshape '((a . b) . (c . d)) '(e f g h))
;=> ((e . f) g . h)
;=> ()
(reshape '((a . b) . (c . d)) '(e f g h i j k))
;=> ((e . f) g . h)
;=> (i j k)          ; leftovers