Scheme 如何使用列表中的元素构造特定形状的树
给定一个s表达式Scheme 如何使用列表中的元素构造特定形状的树,scheme,Scheme,给定一个s表达式”((a.b.)(c.d))和一个列表”(e f g h),我如何遍历s表达式创建一个形状相同但元素取自列表的s表达式?例如,对于上面的s表达式和列表,结果将是”((E.f)g.h)?我假设您希望创建一个新的s表达式,其形状与第一个参数给定的s表达式的形状相同,但第二个参数中的列表元素相同 如果这是正确的,这里有一个可能的解决方案,使用列表来保存我们在替换列表中的位置,并使用Racket来更新列表(如果您的口译员没有更新列表,请使用让,正如Chris和Joshua在评论中建议的那
”((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)
该解决方案类似于我的:
然后
按从左到右的顺序遍历成对树并不特别困难,因为car和cdr可以让你到达两边,而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