Lambda 小阴谋家:卡在multiinsertLR&;共同示例

Lambda 小阴谋家:卡在multiinsertLR&;共同示例,lambda,scheme,continuations,the-little-schemer,Lambda,Scheme,Continuations,The Little Schemer,经过一些工作后,我能够摸索出multirember&co函数,但我无法真正理解以下multiinsertLR&co代码(第143页): 这本书似乎没有解释在评估函数时应该首先通过哪个collector,因此我使用了第138页和第140页分别解释的a-friendcollector和last friendcollector。使用任一收集器评估函数会导致以下错误(使用带petit-chez方案的跟踪函数): >(multiinsertLR&co“咸”鱼薯条(薯条和鱼或鱼和薯条)最后的朋友) |(mu

经过一些工作后,我能够摸索出
multirember&co
函数,但我无法真正理解以下
multiinsertLR&co
代码(第143页):

这本书似乎没有解释在评估函数时应该首先通过哪个
collector
,因此我使用了第138页和第140页分别解释的
a-friend
collector和
last friend
collector。使用任一收集器评估函数会导致以下错误(使用带petit-chez方案的跟踪函数):

>(multiinsertLR&co“咸”鱼薯条(薯条和鱼或鱼和薯条)最后的朋友)
|(multiinsertLR&co咸炸鱼片(薯条和鱼或鱼和薯条)
#)
|(multiinsertLR&co咸炸鱼片(以及鱼或鱼和薯条)
#)
|(multiinsertLR&co咸炸鱼片(鱼或鱼和薯条)#
|(multiinsertLR&co咸炸鱼片(或鱼和炸鱼片)#
|(multiinsertLR&co咸炸鱼片(鱼和炸鱼片)#
|(multiinsertLR&co咸炸鱼片(和薯条)#
|(multiinsertLR&co咸炸鱼片(薯条)#
|(multiinsertLR&co咸炸鱼片()#)
异常:要添加的参数数量不正确#
键入(debug)以进入调试器。

我检查了代码好几次,但都没有找到错误。如果有人有任何见解,请分享。如果有人也能用一些好的例子(相对而言)给我一个关于continuation的温和解释,我也会非常感激。

正如代码中的基本情况所示,收集器/continuation必须包含3个参数。似乎您传入了一个函数,但该函数没有


很高兴你通过
multirember&co
:我写了一个关于它的答案

无论如何,测试这些收集器/延续的一般方法是首先使用
list
作为延续,因为
list
是可变的,只返回作为列表给出的项目。下面是一个例子:

> (multiinsertLR&co 'foo 'bar 'baz '(foo bar baz qux quux) list)
'((foo foo bar baz foo qux quux) 1 1)
哦,我看到两个
foo
s!插入了哪一个,以及原始列表中的哪一个

> (multiinsertLR&co 'foo 'bar 'baz '(goo bar baz qux quux) list)
'((goo foo bar baz foo qux quux) 1 1)
啊,所以我们有点进展了!每当列表包含
,就会在其前面插入
foo
;每当列表包含
baz
,都会在其后面插入
foo
。但是数字呢

> (multiinsertLR&co 'foo 'bar 'baz '(baz goo bar baz qux bar quux baz) list)
'((baz foo goo foo bar baz foo qux foo bar quux baz foo) 2 3)
那些数字看起来像计数器!每次“左”插入递增第一个计数器,每次“右”插入递增第二个计数器



在查看代码时,如果您查看
cond
的每个分支,您将看到左匹配情况、右匹配情况和不匹配情况(当然还有设置基值/初始值的列表结束情况)中发生的情况。注意在每种情况下插入(和计数器增量)是如何发生的。由于您已经获得了
multirember&co
,从现在开始,这应该相当容易。祝你一切顺利

以下是我解决Chris第二个例子的过程,因为我认为这可能对其他可能陷入困境的人有所帮助。(如果有错误,请更正!)


再次在我最近最喜欢的模式匹配伪代码中重写它,1我们得到了更紧凑、更直观的结果

multiinsertLR&co新的oldL-oldR-lat-col=g lat-col
哪里
g[a,…t]col
|a==oldL=gt(newlat L R=>col[new,oldL,…newlat](add1 L)R)
|a==oldR=gt(newlat L R=>col[oldR,new,…newlat]L(add1 R))
|else=gt(newlat L R=>col[a,…newlat]L R)
g[]列=列[]0 0
所以
L
lat
oldL
s的计数
R
lat
oldR
s的计数;而
new
是一个特殊元素,插入到正在生成的结果列表中,
oldR
的右侧,以及原子
lat
输入列表中
oldL
元素的左侧:

multi&co 0 1 2[1,4,5,2,4,5,1,4,5,1]列
=
列[0,1,4,5,2,0,4,5,0,1,4,5,0,1]3 1
就这些。有了一个有用的符号,这就足够简单了



我明白了。

是的,你完全正确。我再次查看了堆栈跟踪,发现它在终端条件下失败了,实际上,
a-friend
last-friend
函数使用了两个参数,而不是所需的三个参数。我将使用您的方法再次测试它,使用
list
作为延续。此外,我认为使此函数难以分析的原因是,在每个递归步骤中,新的延续由上一个延续、它之前的上一个延续……等组成。我的观察正确吗?而且,我认为我看到的每一个延续都是程序中任何特定点的环境及其状态的“快照”。。。因此,当函数在每个递归步骤中作为参数传递时,每个匿名函数都包含该精确时刻的值,例如,
(car-lat)
,当我们到达终端条件时,最终计算该函数时,
(car-lat)的状态
将与我们最初将其作为参数传递时相同。这听起来对吗?
> (multiinsertLR&co 'foo 'bar 'baz '(goo bar baz qux quux) list)
'((goo foo bar baz foo qux quux) 1 1)
> (multiinsertLR&co 'foo 'bar 'baz '(baz goo bar baz qux bar quux baz) list)
'((baz foo goo foo bar baz foo qux foo bar quux baz foo) 2 3)
;; Anonymous functions (collectors) in mutliinsertLR&co here defined as named  
;; functions for reference purposes
(define left-col
  (lambda (newlat L R)
    (col (cons new
               (cons oldL newlat))
         (add1 L) R)))              ; L counter gets incremented

(define right-col
  (lambda (new lat L R)
    (col (cons oldR
               (cons new newlat))
         L (add1 R))))              ; R counter gets incremented

(define else-col
  (lambda (newlat L R)
    (col (cons (car lat)
               (newlat) L R))))     ; neither counter gets incremented

;; Let's step through an example to see how this works:
;;
;; 1. ENTRY TO FUNCTION
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = (goo bar baz qux quux)
;; col  = list
;;
;; 1. Is lat null? No.
;; 2. Is car of lat equal to oldL? No.
;; 3. Is car of lat equal to oldR? No.
;; 4. Else? Yes. Recur on the function passing the new, oldL
;;    oldR, (cdr lat) and the new collector.
;;
;; 2. FIRST RECURSIVE STEP
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = (bar baz qux quux)
;; col  = else-col
;;
;; - Is lat null? No.
;; - Is car of lat equal to oldL? Yes. Recur on the function
;;   passing new, oldL, oldR, (cdr lat), and the new col.
;;
;; 3. SECOND RECURSIVE STEP
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = (baz qux quux)
;; col  = left-col
;;
;; - Is lat null? No.
;; - Is car of lat equal to oldL? No.
;; - Is car of lat equal to oldR? Yes. Recur on the function
;;   passing new, oldL, oldR, (cdr lat), and the new col.
;;
;; 4. THIRD RECURSIVE STEP
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = (qux quux)
;; col  = right-col
;;
;; - Is lat null? No.
;; - Is car of lat equal to oldL? No.
;; - Is car of lat equal to oldR? No.
;; - Else? Yes. Recur on the function passing new, oldL, oldR,
;;   (cdr lat) and the new collector.
;;
;; 5. FOURTH RECURSIVE STEP
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = (quux)
;; col  = else-col
;;
;; - Is the lat null? No.
;; - Is the car of lat equal to oldL? No.
;; - Is the car of lat equal to oldR? No.
;; - Else? Yes. Recur on the function passing new, oldL, oldR,
;;   (cdr lat) and the new collector.
;;
;; 6. FIFTH RECURSIVE STEP
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = ()
;; col  = else-col
;;
;; - Is the lat null? Yes. Call else-col, where newlat is (),
;;   L is 0 and R is 0.
;;
;; 7. ELSE-COL
;; newlat = ()
;; L      = 0
;; R      = 0
;; col    = else-col
;;
;; - Now call else-col on the (cons (car lat)), which is currently
;;   stored in memory as the atom "quux", onto newlat, as well as
;;   L and R.
;;
;; 8. ELSE-COL (again)
;; newlat = (quux)
;; L      = 0
;; R      = 0
;; col    = right-col
;;
;; - Now call right-col on the (cons (car lat)), which is currently
;;   stored in memory as the atom "qux", onto newlat, as well as L
;;   and R.
;;
;; 9. RIGHT-COL
;; newlat = (qux quux)
;; L      = 0
;; R      = 0
;; col    = left-col
;;
;; - Now call left-col on the cons of oldR and (cons new newlat),
;;   as well as L and the increment of R.
;;
;; 10. LEFT-COL
;; newlat = (baz foo qux quux)
;; L      = 0
;; R      = 1
;; col    = else-col
;;
;; - Now call else-col on the cons of new and (cons oldL newlat),
;;   as well as the increment of L and R.
;;
;; 11. ElSE-COL (last time)
;; newlat = (foo bar baz foo qux quux)
;; L      = 1
;; R      = 1
;; col    = list
;;
;; - Now we call list on the (cons (car lat)), which is currently
;;   stored in memory as the atom "goo", onto newlat, as well as L
;;   and R.
;; - This gives us the final, magical list:
;;   ((goo foo bar baz foo qux quux) 1 1)
;;
;; 12. FIFTH RECURSIVE STEP (redux)
;; new  = foo
;; oldL = bar
;; oldR = baz
;; lat  = (quux)
;; col  = else-col
;;
;; - Base case evaluated, with the result being
;;   ((goo foo bar baz foo qux quux) 1 1).
;; - Function ends.
;;
;; THE END