Scheme 先发制人——老练的阴谋家

Scheme 先发制人——老练的阴谋家,scheme,continuations,callcc,seasoned-schemer,Scheme,Continuations,Callcc,Seasoned Schemer,请看第19章中的two-in-a-row*?函数 我的问题是关于get firsthelper函数中的(leave'())。请注意,(waddle l)将返回”()或一个atom,这表示列表已用尽或从列表中检索到一个atom 没有(leave'())它仍然会返回这两种值,只是不使用continuationleave。但是书上说没有(离开'())是不好的,我就是不明白为什么 (define two-in-a-row* (letrec ([leave id] ; the identity fun

请看第19章中的
two-in-a-row*?
函数

我的问题是关于
get first
helper函数中的
(leave'())
。请注意,
(waddle l)
将返回
”()
或一个atom,这表示列表已用尽或从列表中检索到一个atom

没有
(leave'())
它仍然会返回这两种值,只是不使用continuation
leave
。但是书上说没有
(离开'())
是不好的,我就是不明白为什么

(define two-in-a-row*
  (letrec ([leave id] ; the identity function 
           [fill id]
           [waddle (lambda (l)
                     (cond [(null? l) '()]
                           [(atom? (car l))
                            (begin 
                              (letcc rest
                                     (set! fill rest)
                                     (leave (car l)))
                              (waddle (cdr l)))]
                           [else
                            (begin
                              (waddle (car l))
                              (waddle (cdr l)))]))]
           [get-first (lambda (l)
                        (letcc here
                               (set! leave here)
                               (waddle l)
                               (leave '()) ; why is this part needed???
                               ))]
           [get-next (lambda (l)
                       (letcc here
                              (set! leave here)
                              (fill 'go)))]
           [T? (lambda (a)
                 (let ([n (get-next 'dummy)])
                   (if (atom? n)
                       (or (eq? a n)
                           (T? n))
                       #f)))])
    (lambda (l)
      (let ([fst (get-first l)])
        (if (atom? fst)
            (T? fst)
            #f)))))
非常感谢


关于这个问题,另一个有趣的问题。

命名看起来不合适。我用“屈服”表示“离开”,用“下一步”表示“填充”。我还必须定义
atom?
并将
letcc
重新编写为
call/cc
,以使其在Racket中工作。以下是完整的代码:

(define two-in-a-row*
  (letrec ([yield '()] 
           [next '()]
           [atom? (lambda (x) (and (not (null? x))
                                   (not (pair? x))))]
           [waddle (lambda (l)
                     (cond [(null? l) '()]
                           [(atom? (car l))
                            (begin 
                              (call/cc (lambda ( here2 )
                                          (set! next here2)
                                          (yield (car l))))
                              (waddle (cdr l)))]
                           [else
                            (begin (waddle (car l))
                                   (waddle (cdr l)))]))]
           [get-first (lambda (l)
                        (call/cc (lambda ( here1 )
                                    (set! yield here1)
                                    (waddle l)
                                    (yield '()) ; why is this part needed???
                                    )))]
           [get-next (lambda ()
                       (call/cc (lambda ( here3 )
                                   (set! yield here3)
                                   (next 'dummy))))]
           [T? (lambda (a)
                 (let ([n (get-next)])  (display (list "next:" n))
                   (and (atom? n)
                        (or (eq? a n)
                            (T? n)))))])
    (lambda (l)
      (let ([a (get-first l)])
        (and (begin                     (display (list "first:" a))
                    (atom? a))
             (T? a))))))
我们可以在这里看到区别:

(two-in-a-row* '(((7) (b)) c (d)))
  ; w/out yield () : (first: 7)(next: b)(next: c)(next: d)(first: ())#f
  ; w/    yield () : (first: 7)(next: b)(next: c)(next: d)(next: ())#f
  ; w/    yield #f : (first: 7)(next: b)(next: c)(next: d)(next: #f)(next: #f)#t

(two-in-a-row* '(((7) (b)) c ()))
  ; w/out yield () : (first: 7)(next: b)(next: c)(first: ())#f
  ; w/    yield () : (first: 7)(next: b)(next: c)(next: ())#f
  ; w/    yield #f : (first: 7)(next: b)(next: c)(next: #f)(next: #f)#t

(two-in-a-row* '(((7) (b)) b ()))
  ; w/out yield () : (first: 7)(next: b)(next: b)#t
  ; w/    yield () : (first: 7)(next: b)(next: b)#t
  ; w/    yield #f : (first: 7)(next: b)(next: b)#t

谢谢威尔·内斯的例子。我看了一些更简单的。那么“这有什么不好的?”——没有
(离开“())
进入
先获得

简短回答:
请注意,从我的代码
i) 每次调用
get first
get next
时,都会重新创建
leave
。它将返回到
get first
get next

ii)
fill
将根据前面的
fill
生成一个链,并且它将始终返回到
get first

示例
输入:
”(1)

因此,我们首先对
'(1)

i) 设置离开 ii)启动
(摇摇晃晃)(1)

iii)由于
1
是一个原子,因此将
fill
设置为当前延续。注意:如果我们使用
fill
,那么它将转到do
(waddle(cdr l))
,然后它将返回到
get first
。 iv)使用返回值为
1
leave
返回到
get first

然后我们转到eval
(T?1)
,它将依次运行
get next

i) 设置离开 ii)运行
填充

iii)启动
(摇摇晃晃'())

iv)从
waddle
返回
()
,然后返回到
get first

注意
1) 如果我们没有
(离开“()”
,那么
get first
将返回
”()
,然后
two-in-a-in-a-row*
返回
#f
。因此我们可以得到相同的答案,但行为不是我们想要的。
2) 如果我们有它,那么请注意,
leave
现在是由
get next
创建的
leave
,因此它将把
()
转移到
get next


3) 当我们创建
fill
时,列表中有超过1个输入,它将基于先前的
fill
创建,因此结果是一个链,取决于先前的
fill

这很棘手。书中的线索是
回复。学生在说
()
是从另一个函数返回的

这一点在书中或使用drracket都不清楚,我花了一段时间才理解,但理解这一点的关键是:

  • get first
    调用
    waddle
    使
    填充
    继续
  • waddle
    (不使用continuations时)返回到
    get first
  • 但是

  • get next
    调用
    fill
  • fill
    waddle
  • waddle
    使用
    leave
    返回到
    get next
    而不是
    get first
  • 但是在
    (waddle'())
    的情况下,
    waddle
    不使用
    leave
    返回
    get next
    。它正常返回。这意味着它将返回到
    get first

    这意味着
    get next
    实际上不会获取
    ()
    返回值。它不会获取此值,因为
    waddle
    将返回到
    get first

    现在是有趣的部分

  • 我们知道,对于值
    ()
    waddle
    返回到
    get first
    ,当我们希望它返回到
    get next
  • 我们知道
    get next
    设置
    leave
    返回
    get next
  • 因此,
    get first
    可以使用
    leave
    返回到
    get next
  • 这很棘手的真正原因是,当您在
    get first
    中不使用
    (leave'())
    时,请查看场景

  • ()
    填充
    调用waddle
    
  • waddle
    返回到
    get first
  • get first
    然后返回
    ()
  • 这相当于:

      (let ([fst '()])     ;; was (let ([fst (get-first l)])
        (if (atom? fst)
            (T? fst)
            #f)))))
    
    它返回的值与返回到
    get next
    的版本的值相同:

           [T? (lambda (a)
                 (let ([n '()])      ;; was (let ([n (get-next 'dummy)])
                   (if (atom? n)
                       (or (eq? a n)
                           (T? n))
                       #f)))])
    

    两者都是
    #f
    ,但只是偶然!没有人说这本书不会让你思考;)

    你好@Will Ness,太好了!!!我现在完全明白它的工作原理了。我会给你学分的。“我会把整个事情写在另一个答案里。”凌霄很高兴它对你有所帮助。这是一个真正令人心醉神迷的人