解释《小阴谋家》第 137 页的延续示例

发布于 2024-11-29 01:18:25 字数 788 浏览 2 评论 0原文

有问题的代码是这样的:

(define multirember&co
  (lambda (a lat col)
    (cond
     ((null? lat)
      (col (quote ()) (quote ())))
     ((eq? (car lat) a)
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col newlat
                             (cons (car lat) seen)))))
     (else
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col (cons (car lat) newlat)
                             seen))))))

我整天盯着这个,但我似乎不太明白它。当您重复该函数时,您正在重新定义 col 但在示例中它们似乎使用原始定义。为什么不改变呢。如何在不传入参数 newlatseen 的情况下重复它。

很难解释我的问题,因为我似乎遗漏了一块。如果有人可以给出比这本书更明确的演练,我也许能够理解它是如何工作的。

The code in question is this:

(define multirember&co
  (lambda (a lat col)
    (cond
     ((null? lat)
      (col (quote ()) (quote ())))
     ((eq? (car lat) a)
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col newlat
                             (cons (car lat) seen)))))
     (else
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col (cons (car lat) newlat)
                             seen))))))

I've stared at this all day but I can't quite seem to understand it. When you recur on the function you are re-defining col but in the examples they seem to use the original definition. Why wouldn't it change. How can you recur on it without passing in the parameters newlat and seen.

It's hard to explain my question because I seem to just be missing a piece. If perhaps someone could give a more explicit walk-through than the book I may be able to understand how it works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

好倦 2024-12-06 01:18:25

让我们来看一个例子;也许这会有所帮助。 :-) 为简单起见,我将使用 list 作为收集器/延续,它将仅返回一个包含延续参数的列表。

(multirember&co 'foo '(foo bar) list)

开始时,

a = 'foo
lat = '(foo bar)
col = list

在第一次迭代时,(eq? (car lat) a) 条件匹配,因为 lat 不为空,并且 的第一个元素纬度'foo。这样就设置了 multirember&co 的下一个递归:

a = 'foo
lat = '(bar)
col = (lambda (newlat seen)
        (list newlat (cons 'foo seen))

在下一次迭代中,else 匹配:因为 lat 不为空,并且lat 的第一个元素是 'bar (而不是 'foo)。因此,对于下一次递归,我们有:

a = 'foo
lat = '()
col = (lambda (newlat seen)
        ((lambda (newlat seen)
           (list newlat (cons 'foo seen)))
         (cons 'bar newlat)
         seen))

为了便于人类阅读(并避免混淆),我们可以重命名参数(由于词法范围),而不需要对程序的语义进行任何更改:

col = (lambda (newlat1 seen1)
        ((lambda (newlat2 seen2)
           (list newlat2 (cons 'foo seen2)))
         (cons 'bar newlat1)
         seen1))

最后, (null ? lat) 子句匹配,因为 lat 现在为空。因此,我们称其

(col '() '())

扩展为:

((lambda (newlat1 seen1)
   ((lambda (newlat2 seen2)
      (list newlat2 (cons 'foo seen2)))
    (cons 'bar newlat1)
    seen1))
 '() '())

which(当替换 newlat1 = '()seen1 = '() 时)变为

((lambda (newlat2 seen2)
   (list newlat2 (cons 'foo seen2)))
 (cons 'bar '())
 '())

or (评估 (cons 'bar '( )))

((lambda (newlat2 seen2)
   (list newlat2 (cons 'foo seen2)))
 '(bar)
 '())

现在,替换值 newlat2 = '(bar)seen2 = '(),我们得到

(list '(bar) (cons 'foo '()))

或者,换句话说,

(list '(bar) '(foo))

给出我们的最终结果

'((bar) (foo))

Let's step through an example; maybe that will help. :-) For simplicity, I'm just going to use list as the collector/continuation, which will just return a list with the arguments to the continuation.

(multirember&co 'foo '(foo bar) list)

At the start,

a = 'foo
lat = '(foo bar)
col = list

At the first iteration, the (eq? (car lat) a) condition matches, since lat is not empty, and the first element of lat is 'foo. This sets up the next recursion to multirember&co thusly:

a = 'foo
lat = '(bar)
col = (lambda (newlat seen)
        (list newlat (cons 'foo seen))

At the next iteration, the else matches: since lat is not empty, and the first element of lat is 'bar (and not 'foo). Thus, for the next recursion, we then have:

a = 'foo
lat = '()
col = (lambda (newlat seen)
        ((lambda (newlat seen)
           (list newlat (cons 'foo seen)))
         (cons 'bar newlat)
         seen))

For ease of human reading (and avoid confusion), we can rename the parameters (due to lexical scoping), without any change to the program's semantics:

col = (lambda (newlat1 seen1)
        ((lambda (newlat2 seen2)
           (list newlat2 (cons 'foo seen2)))
         (cons 'bar newlat1)
         seen1))

Finally, the (null? lat) clause matches, since lat is now empty. So we call

(col '() '())

which expands to:

((lambda (newlat1 seen1)
   ((lambda (newlat2 seen2)
      (list newlat2 (cons 'foo seen2)))
    (cons 'bar newlat1)
    seen1))
 '() '())

which (when substituting newlat1 = '() and seen1 = '()) becomes

((lambda (newlat2 seen2)
   (list newlat2 (cons 'foo seen2)))
 (cons 'bar '())
 '())

or (evaluating (cons 'bar '()))

((lambda (newlat2 seen2)
   (list newlat2 (cons 'foo seen2)))
 '(bar)
 '())

Now, substituting the values newlat2 = '(bar) and seen2 = '(), we get

(list '(bar) (cons 'foo '()))

or, in other words,

(list '(bar) '(foo))

to give our final result of

'((bar) (foo))
dawn曙光 2024-12-06 01:18:25

我在这里找到了一个很棒的答案:
http://www.michaelharrison.ws/weblog/?p=34

我一直在努力解决这个问题也。关键是理解词法作用域(对我来说,是 Javascript)以及在 eq 和 not eq 分支上传递给 multirember&co 的内部函数。明白了这一点,你就会明白整个过程。

I found a wonderful answer here:
http://www.michaelharrison.ws/weblog/?p=34

I've been struggling through this too. The key is to understand lexical scoping (for me, à la Javascript) and the inner functions passed to multirember&co on the eq and not eq branches. Understand that, and you'll understand the entire procedure.

不疑不惑不回忆 2024-12-06 01:18:25

很长一段时间以来,我一直在努力理解 multirember&co 内部发生的事情。问题是,当我以为我已经得到它的那一刻 - 下一个任务/示例证明我还没有。

对我有帮助的是整合正在发生的事情的视觉表示(对我来说,文本演练很难理解,出于某种原因)。

所以,我整理了两个流程图:

一,仅显示不同递归步骤之间的关系


还有另一个,反映实际值

视觉演练价值观

现在,每当我感觉自己又失去了“争论的线索”时,我只要参考这个流程图,它就会让我回到正轨。

通过流程图查看“全貌”后我明白的另一件事是,a-friend函数只是检查是否seen是否保存任何值(尽管它以相反的方式返回它,即当 seen 中有值时 #f#tsaw 是空的,这可能会令人困惑

PS:我 。为evens-only*&co做了类似的流程图,稍后出现在书。

I have struggled myself, to understand what is happening inside the multirember&co, for quite a while. The problem is that the moment I thought I've got it - next task/example proved I have not.

What helped me was putting together a visual representation of what is happening (for me text walkthroughs are tough to grasp, for some reason).

So, I have put together two flow-charts:

One, just showing the relations between different steps of recursion:

Visual walkthrough showing relations


And another one, reflecting actual values:

Visual walkthrough with values

Now, whenever I feel like I'm loosing 'the thread of an argument' again, I just refer to this flow-charts and it puts me back on track.

Another thing I've understood after looking at the 'whole picture' via flow-chart, is that a-friend function is simply checks whether seen holds any values or not (though it returns it the other way around i.e. #f when there values in seen and #t when seen is empty, which might be confusing.

P.S.: I did similar flow-charts for evens-only*&co, which appears later in the book.

稀香 2024-12-06 01:18:25

上面的链接(http://www.michaelharrison.ws/weblog/?p=34)很好地解释了整个练习是如何避免命令式编程(C,Java)需要声明两个“持有者”或“收集器” “变量(或列表、向量)显式地存在于内存中,以便在您迭代列表时捕获您的答案。通过 FP 语言方案使用延续,您在单步执行(草莓金枪鱼和剑鱼)时不会将测试结果“推送”到任何单独创建的“篮子”中;相反,当您发送适当的 consing 函数时,您将两个列表组合在一起 - 一个用于 eq?是的,另一个为 eq? false——通过重复。 。 。最后结束于第三个 col 函数,在 TLS 的第一个示例中,它是“a-friend”,它询问为保存所有匹配而构建的列表是否为空(null?)。然后,TLS 会要求您使用新的“最后”列再次“运行”multirember&co,该列仅询问包含所有“非金枪鱼”原子的列表包含多少个(“最后朋友”)。因此,有两个“一流”函数用于处理收集任务,即构建两个单独的列表,然后在递归展开结束时,原始 col(“朋友”)提出最终问题。也许“multirember&co”这个名字并不是最伟大的名字,因为它实际上不会重建列表减去要删除的原子;相反,它构建两个单独的列表(永远不会显示),然后应用最终的 col (a-friend 或 last-friend) 。 。 。它显示#t 或#f,或“非金枪鱼”列表的长度。

这是一些输出:

> (multirember&co 'tuna '(and tuna) a-friend)
#f
> (multirember&co 'tuna '(and not) a-friend)
#t

这是一个返回不匹配列表的列:

(define list-not  (lambda (x y) x))

及其用途:

> (multirember&co 'tuna '(and not) list-not)
(and not)

What the link above (http://www.michaelharrison.ws/weblog/?p=34) explains well is how this whole exercise is about avoiding the imperative programming (C, Java) need to declare two "holder" or "collector" variables ( or lists, vectors) explicitly in memory to catch your answers as you iterate through the list. With FP language Scheme's use of continuation, you do not "push" the test results as you step through (strawberries tuna and swordfish) into any separately created "baskets;" instead, you are consing together two lists as you send the appropriate consing functions -- one for eq? true, the other for eq? false -- through the recurs . . . finally ending up at the third col function which, in TLS's first example, is "a-friend" which asks whether the list built to hold all the matches is empty (null?). TLS then asks you to "run" multirember&co again with a new "last" col that merely asks the list containing all the "not tuna" atoms how many it contains ("last-friend"). So there are two "first class" functions being used to work with the task of collecting, i.e. building two separate lists, then at the end of the recursion unwinding, the original col ("a-friend") ask the final question. Maybe the name "multirember&co" is not the greatest name, because it really doesn't rebuild the list minus the atom to be removed; rather, it builds two separate lists -- which never get displayed -- then applies the final col (a-friend or last-friend) . . . which displays either #t or #f, or the length of the "not tuna" list.

Here's some output:

> (multirember&co 'tuna '(and tuna) a-friend)
#f
> (multirember&co 'tuna '(and not) a-friend)
#t

Here's a col to give back a list of non-matches:

(define list-not  (lambda (x y) x))

and its use:

> (multirember&co 'tuna '(and not) list-not)
(and not)
好倦 2024-12-06 01:18:25

让我们使用一些等式伪代码,为了清楚起见,省略了一些括号(因此,我们为调用 (fxy) 编写 fx y,这是明确的)

multirember&Co a lat col
    = col [] []                                , IF lat == [] 

    = multirember&Co a (cdr lat)
         ( newlat seen => 
             col newlat
                 (cons (car lat) seen) )       , IF (car lat) == a

    = multirember&Co a (cdr lat)
         ( newlat seen => 
             col (cons (car lat) newlat)
                 seen )                        , OTHERWISE

:不言而喻,这是做什么的? :) 还没有? :) 用想象中的模式匹配伪代码(带有守卫)再次重写,我们有

multirember&Co  =  g   where
    g a [b, ...lat] col | b == a  =  g a lat ( n s =>  col     n     [b, ...s] )
                        | else    =  g a lat ( n s =>  col [b, ...n]     s     )
    g a []          col           =                    col     []        []

模式匹配的语义应该非常明显: [b, ...lat] 匹配 [ 1,2,3],其中 b = 1lat = [2,3]。因此,这只是一个三例方程:

  • 当第二个参数是空列表时,“收集器”函数 col 立即被输入两个空列表作为其两个参数;

  • 当第二个参数(是一个列表)的head元素与第一个参数相同时,结果与使用以下tail递归的结果相同列表,带有修改后的收集器 - 之后它将收到两个参数,ns,--将< /em> 在当前头元素前面添加(即a) 到 s 列表,并将这两个列表提供给 this 调用的收集器函数 col;

  • 否则,在构建的收集器接收到 ns 后,头元素将被添加到 n 列表中,并且两者都将被进一步馈送到当前收集器函数中。

换句话说,我们正在处理从递归调用返回的两个结果,如果头是a,则将头添加到第二个结果,如果不是,则将头添加到第一个结果。

因此,调用

    (g 1 [ 2, 1, 3, 1, 4, 5 ] col)

与调用相同(将导致),

    (col [ 2, ...[3, ...[4, ...[5, ...[]]]]]
         [    1, ...[1,            ...[]]  ])

    (col [ 2,     3,     4,     5          ]
         [    1,     1                     ])

另一种看待它的方式是,以下是另一个等效的公式:

multirember&Co a lat col  =  g a lat id id   where
    id      x  =  x              ; identity function  
    (f ∘ g) x  =  f (g x)        ; function composition
    g a [b, ...lat] c d 
               | b == a  =  g a lat  c     (d ∘ (x => cons b x))  ;    (d ∘ {cons b})
               | else    =  g a lat (c ∘ (x => cons b x))   d     ; (c ∘ {cons b})
    g a []          c d  =  col     (c [])                (d [])

因此,

multirember&Co 1 [ 2, 1, 3, 1, 4, 5 ] col 
=
col (((((id ∘ {cons 2}) ∘ {cons 3}) ∘ {cons 4}) ∘ {cons 5}) [])   ; { } is for
    ( ( (id ∘       {cons 1}) ∘ {cons 1}                  ) [])   ;  partial application
=
col     (id   (cons 2     (cons 3     (cons 4    (cons 5   [])))))
        (id         (cons 1     (cons 1                    []) ) )  

这是不言而喻的同一件事。

在另一个伪代码(带有列表推导)中,这表明它只

multirember&Co a lat col  
   = col [ b for b in lat if (b /= a) ] 
         [ b for b in lat if (b == a) ] 
   = ( ((n,s) => col n s) ∘ {partition {/= a}} ) lat

执行一次列表 lat 遍历(在原始代码中),有效地构建模仿原始列表结构的 lambda 函数的嵌套链;然后评估该链以创建两个结果,并将它们传递给最顶层的收集器函数 col

所有这些都向我们展示了Continuation-Passing Style的力量(这就是它)实际上,创建自己的函数调用协议,例如,从每个递归函数调用传回两个结果,即使通常在 lambda 演算中函数只能有一个 > 结果(即使是一对)。

Let's use some equational pseudocode with some parentheses omitted for clarity (so, we write f x y for the call (f x y), where this is unambiguous):

multirember&Co a lat col
    = col [] []                                , IF lat == [] 

    = multirember&Co a (cdr lat)
         ( newlat seen => 
             col newlat
                 (cons (car lat) seen) )       , IF (car lat) == a

    = multirember&Co a (cdr lat)
         ( newlat seen => 
             col (cons (car lat) newlat)
                 seen )                        , OTHERWISE

Isn't it just self-evident, what this does? :) Not yet? :) Re-writing again with an imagined pattern-matching pseudocode (with guards), we have

multirember&Co  =  g   where
    g a [b, ...lat] col | b == a  =  g a lat ( n s =>  col     n     [b, ...s] )
                        | else    =  g a lat ( n s =>  col [b, ...n]     s     )
    g a []          col           =                    col     []        []

The semantics of pattern matching should be quite obvious: [b, ...lat] matches [1,2,3] where b = 1 and lat = [2,3]. This is thus just a three-cased equation:

  • When the second argument is an empty list, the "collector" function col is fed two empty lists as its two arguments right away;

  • When the second argument's (which is a list) head element is the same as the first argument, the result is the same as that for recursing with the tail of the list, with the amended collector which -- after it will receive its two arguments, n and s, -- will prepend the current head element (which is a) to the s list, and will feed the two lists to this invocation's collector function col;

  • Otherwise, the head element will be prepended to the n list, after n and s are received by the constructed collector, and the both will be fed further into the current collector function.

In other words we're dealing with two results coming back from the recursive call, prepending the head to the second if the head was a, or to the first if it wasn't.

Thus the call

    (g 1 [ 2, 1, 3, 1, 4, 5 ] col)

is the same as (will result in) the call

    (col [ 2, ...[3, ...[4, ...[5, ...[]]]]]
         [    1, ...[1,            ...[]]  ])

i.e.

    (col [ 2,     3,     4,     5          ]
         [    1,     1                     ])

Another way to look at it is that the following is another, equivalent formulation:

multirember&Co a lat col  =  g a lat id id   where
    id      x  =  x              ; identity function  
    (f ∘ g) x  =  f (g x)        ; function composition
    g a [b, ...lat] c d 
               | b == a  =  g a lat  c     (d ∘ (x => cons b x))  ;    (d ∘ {cons b})
               | else    =  g a lat (c ∘ (x => cons b x))   d     ; (c ∘ {cons b})
    g a []          c d  =  col     (c [])                (d [])

and thus

multirember&Co 1 [ 2, 1, 3, 1, 4, 5 ] col 
=
col (((((id ∘ {cons 2}) ∘ {cons 3}) ∘ {cons 4}) ∘ {cons 5}) [])   ; { } is for
    ( ( (id ∘       {cons 1}) ∘ {cons 1}                  ) [])   ;  partial application
=
col     (id   (cons 2     (cons 3     (cons 4    (cons 5   [])))))
        (id         (cons 1     (cons 1                    []) ) )  

which is self-evidently the same thing.

In yet another pseudocode (with list comprehensions), this reveals itself to be

multirember&Co a lat col  
   = col [ b for b in lat if (b /= a) ] 
         [ b for b in lat if (b == a) ] 
   = ( ((n,s) => col n s) ∘ {partition {/= a}} ) lat

except that only one traversal of the list lat is performed (in the original code), efficiently, building the nested chain of lambda functions mimicking the original list structure; which chain is then evaluated to create the two results, passing them to the top-most collector function col.

All this shows us the power of Continuation-Passing Style (which is what this is) to, in effect, create its own function call protocol, here for example passing back two results from each recursive function call, even though normally in lambda calculus a function can only have one result (even if, say, a pair).

白云悠悠 2024-12-06 01:18:25

该代码不会像通常那样构建解决方案,而是构建一个计算解决方案的代码,就像使用低级操作构建树一样,例如 cons+- 等,而不是使用高级累加器或过滤器。

这就是为什么很难说该过程是迭代的还是递归的,因为根据迭代过程的定义,它们为本地状态使用有限量的内存。然而,这种进程使用大量内存,但这是在环境中分配的,而不是在本地参数中分配的。

首先,我在这里复制代码,以便能够在不滚动太多的情况下查看对应关系:

(define multirember&co
  (lambda (a lat col)
    (cond
     ((null? lat)
      (col (quote ()) (quote ())))
     ((eq? (car lat) a)
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col newlat
                             (cons (car lat) seen)))))
     (else
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col (cons (car lat) newlat)
                             seen)))))))

让我们尝试拆分问题,看看到底发生了什么。

  • 情况 1:

(multirember&co 'a
                '()
                (lambda (x y) (list x y)))

is the same as    

(let ((col (lambda (x y) (list x y))))
  (col '() '()))

这是一个简单的情况,它永远不会循环。

现在是有趣的案例:

  • 案例 2:

(multirember&co 'a
                '(x)
                (lambda (x y) (list x y)))

is the same as    

(let ((col
       (let ((col (lambda (x y) (list x y)))
             (lat '(x))
             (a 'a))
         (lambda (newlat seen)
           (col (cons (car lat) newlat)
                seen)))))
  (col '() '()))

在这种情况下,流程生成此代码作为结果,并最终对其进行评估。请注意,本地它仍然是尾递归的,但全局它是一个递归过程,并且它需要内存不是通过分配某些数据结构,而是通过让评估器仅分配环境帧。每个循环都会通过添加 1 个新框架来加深环境。

  • 情况 3

(multirember&co 'a
                '(a)
                (lambda (x y) (list x y)))

is the same as    

(let ((col
       (let ((col (lambda (x y) (list x y)))
             (lat '(a))
             (a 'a))
         (lambda (newlat seen)
           (col newlat
                (cons (car lat) seen))))))
  (col '() '()))

这构建了代码,但在另一个分支上,将结果累积到另一个变量中。


所有其他情况都是这 3 种情况中 1 种的组合,通过添加新层,每个 1 的作用就很清楚了。

The code does not build the solution, as it happens usually, but it builds a code that computes the solution, exactly as when you would build the tree using low level operations, like cons, +, -, etc, instead of using high level accumulators or filters.

This is why it is difficult to say if the process is iterative or recursive, because, by the definition of the iterative processes, they use a finite amount of memory for the local state. However, this kind of process uses much memory, but this is allocated in environment, not in local parameters.

First, I duplicate the code here, to be able to see the correspondence without scrolling too much:

(define multirember&co
  (lambda (a lat col)
    (cond
     ((null? lat)
      (col (quote ()) (quote ())))
     ((eq? (car lat) a)
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col newlat
                             (cons (car lat) seen)))))
     (else
      (multirember&co a
                      (cdr lat)
                      (lambda (newlat seen)
                        (col (cons (car lat) newlat)
                             seen)))))))

Let us try to split the problem to see what really happens.

  • Case 1:

(multirember&co 'a
                '()
                (lambda (x y) (list x y)))

is the same as    

(let ((col (lambda (x y) (list x y))))
  (col '() '()))

This is a trivial case, it never loops.

Now the interesting cases:

  • Case 2:

(multirember&co 'a
                '(x)
                (lambda (x y) (list x y)))

is the same as    

(let ((col
       (let ((col (lambda (x y) (list x y)))
             (lat '(x))
             (a 'a))
         (lambda (newlat seen)
           (col (cons (car lat) newlat)
                seen)))))
  (col '() '()))

In this case, the process produces this code as result, and finally evaluates it. Note that locally it is still tail-recursive, but globally it is a recursive process, and it requires memory not by allocating some data structure, but by having the evaluator allocate only environment frames. Each loop deepens the environment by adding 1 new frame.

  • Case 3

(multirember&co 'a
                '(a)
                (lambda (x y) (list x y)))

is the same as    

(let ((col
       (let ((col (lambda (x y) (list x y)))
             (lat '(a))
             (a 'a))
         (lambda (newlat seen)
           (col newlat
                (cons (car lat) seen))))))
  (col '() '()))

This builds the code , but on the other branch, that accumulates a result in the other variable.


All the other cases are combinations of 1 of these 3 cases, and it is clear how each 1 acts, by adding a new layer.

无人接听 2024-12-06 01:18:25

我希望本演练有所帮助

正如 Chris 建议的那样,我已将 newlat/seen 重命名为 n/s 并添加了索引。
这本书给函数起了可怕的名字(a-friend new-friend Latest-fried),所以我只保留了 L(代表 lambda)和定义。

multirember&co 'tuna '(strawberries tuna and swordfish) a-friend)
  multirember&co 'tuna '(tuna and swordfish) (L(n1 s1)(a-friend (cons 'strawberries n1) s1))
    multirember&co 'tuna '(and swordfish) (L(n2 s2)((L(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))
      multirember&co 'tuna '(swordfish) (L(n3 s3)((L(n2 s2)((L(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2)) (cons 'and n3) s3))
        multirember&co 'tuna '() (L(n4 s4)((L(n3 s3)((L(n2 s2)((L(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2)) (cons 'and n3) s3)) (cons 'swordfish n4) s4))

((lambda(n4 s4)((lambda(n3 s3)((lambda(n2 s2)((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))) (cons 'and n3) s3)) (cons 'swordfish n4) s4)) '() '())
               ((lambda(n3 s3)((lambda(n2 s2)((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))) (cons 'and n3) s3)) '(swordfish) '())
                              ((lambda(n2 s2)((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))) '(and swordfish) '())
                                             ((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) '(and swordfish) '(tuna))
                                                            (a-friend '(strawberries and swordfish) '(tuna))

I hope this walkthrough helps

As Chris suggested, I've renamed newlat/seen to n/s and added an index.
The book gives horrible names to the functions (a-friend new-friend latest-fried), so I just kept L (for lambda) and the definition.

multirember&co 'tuna '(strawberries tuna and swordfish) a-friend)
  multirember&co 'tuna '(tuna and swordfish) (L(n1 s1)(a-friend (cons 'strawberries n1) s1))
    multirember&co 'tuna '(and swordfish) (L(n2 s2)((L(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))
      multirember&co 'tuna '(swordfish) (L(n3 s3)((L(n2 s2)((L(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2)) (cons 'and n3) s3))
        multirember&co 'tuna '() (L(n4 s4)((L(n3 s3)((L(n2 s2)((L(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2)) (cons 'and n3) s3)) (cons 'swordfish n4) s4))

((lambda(n4 s4)((lambda(n3 s3)((lambda(n2 s2)((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))) (cons 'and n3) s3)) (cons 'swordfish n4) s4)) '() '())
               ((lambda(n3 s3)((lambda(n2 s2)((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))) (cons 'and n3) s3)) '(swordfish) '())
                              ((lambda(n2 s2)((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) n2 (cons 'tuna s2))) '(and swordfish) '())
                                             ((lambda(n1 s1)(a-friend (cons 'strawberries n1) s1)) '(and swordfish) '(tuna))
                                                            (a-friend '(strawberries and swordfish) '(tuna))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文