【问题标题】:Scheme continuation restarting in weird place计划继续在奇怪的地方重新启动
【发布时间】:2011-05-08 06:34:52
【问题描述】:

更新:

所以问题似乎出在生成器上,不一定与下一个令牌和前瞻功能有关。我在 set!s 发生的地方添加了一些显示调用,发现问题是在第二次调用 (generate-token) 之后,它从第一次调用的位置恢复执行。

这是该程序的完整代码(我在下面留下了原始帖子以供参考):

(define char-alphanumeric? (lambda (char) (or (char-alphabetic? char) (char-numeric? char))))

(define generate-token #f)
(define filename "input.txt")

(define next-token #f)
(define lookahead #f)
(define status #f)

(let ((f (open-input-file filename)) (yield #f) (token "") (lookahead-token #f) (current-token #f))
  (set! generate-token (lambda ()
                     (letrec ((next-char (lambda (c)
                                            (let ((separators (list #\; #\,)))
                                              (cond ((eof-object? c) (display "last token before eof: ") (display token) (newline) (yield c))
                                                    ((member c separators)
                                                     (begin
                                                            (display "token before sep: ") (display token) (newline)
                                                            (call-with-current-continuation (lambda (resume)
                                                                                              (set! generate-token (lambda () (resume)))
                                                                                              (yield token)))
                                                            (display "back from call") (set! token "")
                                                            (call-with-current-continuation (lambda (resume)
                                                                                              (set! generate-token (lambda () (resume)))
                                                                                              (yield (make-string 1 c))))
                                                            ))
                                                    ((or (char-alphanumeric? c) (equal? c #\_)) ; c is part of a string token
                                                     (begin (display "found char: ") (display c) (display "; added to string: ")
                                                            (set! token (string-append token (make-string 1 c)))
                                                            (display token) (newline)
                                                            (next-char (read-char f))))
                                                    ((char-whitespace? c)
                                                     (begin
                                                            (display "token before ws: ") (display token) (newline)
                                                            (if (> (string-length token) 0)
                                                                (begin (call-with-current-continuation (lambda (resume)
                                                                                              (display "setting generate-token to resume") (newline)
                                                                                              (set! generate-token (lambda ()
                                                                                                                 ((display "calling resume") (newline)
                                                                                                                 (resume))))
                                                                                              (display "yielding token from cc") (newline)
                                                                                              (yield token)))
                                                                 (display "continuing...") (newline)
                                                                (set! token ""))
                                                                ;(set! token "")
                                                                ))))
                                              (next-char (read-char f))
                                              ))))
                       (call-with-current-continuation (lambda (k) ((set! yield k) (k (next-char (read-char f))))))
                       )))
  (set! lookahead (lambda () (begin
                              (if (not lookahead-token)
                                  (begin (display "no lookahead") (newline)
                                         (display "setting lookahead-token") (newline)
                                         (set! lookahead-token (string-copy (generate-token)))
                                         (display "lookahead set to ") (display lookahead-token) (newline)
                                         ))
                             lookahead-token)))
  (set! next-token (lambda () (begin
                               (if lookahead-token
                                  (begin (display "affirmative") (newline)
                                         (set! current-token (string-copy lookahead-token))
                                         (set! lookahead-token #f))
                                  (begin (display "negative") (newline)
                                         (display "setting current token to next-token") (newline)
                                         (set! current-token (string-copy (generate-token)))
                                         (display "current token = ") (display current-token) (newline)
                                         (set! lookahead-token #f)))
                               current-token)))
  (set! status (lambda () (begin (display current-token) (display " -> ") (display lookahead-token) (newline))))
)

按照下面原始帖子中的第一个示例执行下一个令牌和前瞻调用会产生:

> (next-token)
negative
setting current token to next-token
found char: t; added to string: t
found char: h; added to string: th
found char: e; added to string: the
found char: s; added to string: thes
found char: e; added to string: these
token before ws: these
setting generate-token to resume
yielding token from cc
current token = these
"these"
> (status)
these -> #f
> (lookahead)
no lookahead
setting lookahead-token
calling resume
continuing...
found char: a; added to string: a
found char: r; added to string: ar
found char: e; added to string: are
token before ws: are
setting generate-token to resume
yielding token from cc ; the problem is right here: the generate token call is
current token = are    ; sending control back to next-token instead of lookahead.
"are"
> (status)
are -> #f

我不知道它为什么会这样,但我承认我是新手,可能不完全理解后果。一如既往,我们将不胜感激任何帮助。

谢谢。

原帖如下:


我创建了一个生成器,它解析一个文本文件并以字符串的形式一次返回一个标记。所以,如果我有一个文件包含

these are my file contents

对 (generate-token) 的连续调用分别返回 "这些" "是" "我的" ...。这似乎有效,但是我将其作为解析器的一部分编写为更大的任务。生成器似乎工作顺利,但是当我正在构建一个 LR(1) 解析器来解析令牌流时,我需要能够执行前瞻。为此,我创建了以下程序:

(define generate-token #f)
(define next-token #f)
(define lookahead #f)
(define status #f)

(let ((lookahead-token #f) (current-token #f))
  (set! generate-token (lambda () ... ) ; the generator function
  (set! lookahead (lambda () (begin
                              (if (not lookahead-token)
                                  (begin (display "no lookahead") (newline)
                                   (set! lookahead-token (string-copy (generate-token)))))
                             lookahead-token)))
  (set! next-token (lambda () (begin
                               (if lookahead-token
                                  (begin (display "affirmative") (newline)
                                         (set! current-token (string-copy lookahead-token))
                                         (set! lookahead-token #f))
                                  (begin (display "negative") (newline)
                                         (set! current-token (string-copy (generate-token)))
                                         (set! lookahead-token #f)))
                                  current-token)))
  (set! status (lambda () (begin (display current-token) (display " -> ") (display lookahead-token) (newline))))
)

但是,这些并没有按预期工作。我的印象是方案(这是用drRacket编写的,但使用#lang r5rs)按值传递对象,所以(字符串复制调用假设是不必要的,但这仍然不能按预期工作。它像这样工作:

> (status)
#f -> #f
> (next-token)
"these"
> (status) ; next-token properly sets current-token 
"these" -> #f
> (lookahead) ; generator returns "are" as expected
"are"
> (status) ; notice that the current-token has been replaced instead of the lookahead-token 
"are" -> #f

在不同的流程中,如果先调用 (lookahead),它会正常工作。

> (status)
#f -> #f
> (lookahead)
"these"
> (status)
#f -> "these"
> (lookahead)
"these"
> (status)
#f -> "these"
> (next-token)
"these"
> (status)
"these" -> #f
> (lookahead)
"are"
> (status)
"these" -> "are"

如果有人对正在发生的事情有任何线索,我们将不胜感激。披露:这是学校作业,但我不是要你为我做这件事>.>。

【问题讨论】:

  • 您的代码与您稍后显示的不匹配——在代码中,这些函数使用set!,因此它们不会返回任何有用的值。 (并且打印输出也不在 repl 示例中。)
  • “我的印象是 scheme 按值传递对象,因此(假设不需要字符串复制调用”不,Scheme 确实按值传递事物,但这些值是引用。字符串变量引用仍可能被修改。方案字符串是可变的(使用字符串集!),所以字符串复制一般来说是必要的。但是由于你在这里没有改变任何字符串,所以它不是必要的。
  • @Eli 你是对的。我错误地复制了代码以在下一个令牌函数中排除最终的“当前令牌))”(它与前瞻函数中的前瞻令牌的返回相匹配)。我不知道我是怎么做到的。我已经添加了return语句,谢谢。
  • 你在这方面有什么进展吗? (我刚刚浏览了continuations 标签,因为最近有一个与生成器相关的问题call-with-current-continuation - state saving concept。)

标签: scope scheme racket continuations callcc


【解决方案1】:

问题在于您对yield 的实现。为了便于阅读,以下是您的实现的简化版本:

(define yield #f)
(define my-generator
        (lambda ()
           (let forever ((num 0))
               (let/cc resume
                  (set! my-generator resume)
                  (yield num))
               (forever (add1 num)))))

(define zero (let/cc my-yield
                (set! yield my-yield)
                (my-generator)))
(define one (my-generator))
zero
;; => 1

一个延续总是跳回到它原来的返回值。因此,如果您使用call/cclet/cc 捕获yield,那么每次您yield 时,您都会跳回到捕获它的位置。

在您的代码中,您花时间在每个 yield 之前更新您的简历延续,但您只在您要去的一个地方更新 yield 致电next-token。每次要拨打 generate-token 时,您都需要更新 yield

对于那些不是为学校做这件事的读者,只需使用racket/generator,所有的工作和更多的工作都在其中完成。

【讨论】:

    猜你喜欢
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多