请参阅第19章中的two-in-a-row*?
功能。
我的问题是关于(leave '())
辅助函数中的get-first
。请注意,(waddle l)
将返回'()
或原子,表示列表已用尽或列表中的原子被检索。
如果没有(leave '())
,它仍会返回这两种值,只是不使用延续leave
。但这本书说没有(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)))))
非常感谢。
关于这个问题的另一个有趣的tread。
答案 0 :(得分:1)
非常感谢Will Ness的例子。我去了一些更简单的。所以“那是多么糟糕?” - (leave '())
中没有get-first
。
简答:
请注意,从我的代码中
i)每次调用leave
或get-first
时,都会重新创建get-next
。它将返回get-first
或get-next
ii)fill
将成为一个链,取决于之前的fill
,它将始终返回get-first
。
示例强>
输入:'(1)
因此,我们首先评估get-first
上的'(1)
i)设置leave
ii)开始(waddle '(1)
iii)因为1
是一个原子,所以将fill
设置为当前继续。请注意,如果我们使用fill
,那么它会转到(waddle (cdr l))
,然后它将返回get-first
。
iv)使用返回值为get-first
的{{1}}返回leave
。
然后我们转到评估1
,然后依次运行(T? 1)
i)设置get-next
ii)运行leave
iii)开始fill
iv)从(waddle '())
返回()
,然后返回waddle
。
注意强>
1)如果我们没有get-first
,则(leave '()
将返回get-first
,然后'()
返回two-in-a-row*
。所以我们可以得到相同的答案,但行为不是我们想要的
2)如果我们拥有它,请注意#f
现在是由leave
创建的leave
,因此它会将get-next
转移到'()
。<登记/>
3)当我们创建get-next
时,列表中有超过1个输入,它将根据之前的fill
创建,从而产生一个取决于先前fill
的链。
答案 1 :(得分:0)
命名视线。我使用“yield”表示“leave”,“next”表示“fill”。我还必须定义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
答案 2 :(得分:0)
这很棘手。书中的线索是wow!
的答复。学生说wow!
是因为他们意识到()
是从其他函数返回的。
这不是很清楚,无论是在书中还是在使用drracket时,都花了我一段时间来理解,但是了解这一点的关键是:
get-first
称为waddle
以使fill
延续。 waddle
(不使用延续时)将返回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
返回到(leave '())
。之所以棘手,真正的原因是看一下在get-first
中不使用fill
的情况。
()
呼叫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
两个都是data =[
{
_id: "5ba241b4efa8da2f1464ca81",
title: "Zero To One",
author: "Peter Thiel",
isbn: 1279031943,
__v: 0
}
]
,但只是偶然!没有人说这本书不会让你思考;)