Racket中的SICP Ch5 eceval编译器:set-cdr!进入引用列表(不是重复)

时间:2019-03-24 18:26:17

标签: scheme racket sicp

这不是重复的 set-car!, set-cdr! unbound in racket?或 的 Implement SICP evaluator using Racket 或的 How to install sicp package module in racket?, 而是一个后续问题,因为其中提出的解决方案没有 为我工作。首先,需要:SICP的5.5.5节,编译器加上 显式控制评估器(code here in "ch5-eceval-compiler.scm")是 完全依赖set-car!set-cdr!到显式引用列表中。一世 想要复制和修改此代码,而无需完全自下而上的重写 不变的形式。我也会接受对可以实现的方案实现的引用 开箱即用地运行代码,或进行一些最少,直接的修改, 即具有set-car!set-cdr!或某些 解决方法。狡猾的人和球拍都无法让我轻松地运行此代码。

EDIT :mit方案将加载eceval编译器。我把问题留给那些可能想要用球拍打发的人(例如,我更愿意)。

这里有更深入的解释,包括我探索和尝试过的东西,以及 我如何将报价单诊断为最深层的问题。当我手动转换时 将引号列表放入mquoted的{​​{1}}嵌套中,代码崩溃的情况更糟 方式和兔子洞变得更深了。我经过几次 数小时的精细脑部手术失败了。

这是5.5.5节所依赖的那种MVE。这很小,但结构上像真实的东西:

mlists

真实的东西是这样开始的:

(define foo '(a b))
(set-cdr! foo '(c))

并持续了一段时间。评估者是引号中的“机器代码” 列表,各种生成的代码会将(define eceval (make-machine '(exp env val proc argl continue unev compapp ;*for compiled to call interpreted ) eceval-operations ;; ---------------------------------------------- '( ;; <<<<<<<<======== BIG QUOTED LIST CAUSING TROUBLE / NOT MCONSES! ;;SECTION 5.4.4, as modified in 5.5.7 ;; ------------------------------- ;;*for compiled to call interpreted (from exercise 5.47) (assign compapp (label compound-apply)) ;;*next instruction supports entry from compiler (from section 5.5.7) (branch (label external-entry)) read-eval-print-loop (perform (op initialize-stack)) (perform (op prompt-for-input) (const ";;; EC-Eval input:")) ... set-car!写入寄存器 和环境框架等。代码加载失败。

似乎没有简单的方法可以将评估程序转换为不可变形式 没有完整的重写,我正在努力避免这种情况。当然,set-cdr!set-car!中没有set-cdr!,我认为它们不在 guile,或者(至少guile拒绝加载“ ch5-eceval-compiler.scm”, 抛出一个可变性错误,对此我没有做更深入的研究。

set-car!, set-cdr! unbound in racket?是 根据{{​​1}}使用#lang racketmconsmcar等重写代码。那些兼容性 软件包无法替代mlist,因此我尝试编写自己的(require compatibility/mlist) (require rnrs/mutable-pairs-6)。一世 在这样的重构上花了几个小时,但是练习没有 会聚,只是越来越深地钻入兔子洞,最后变成 更深层次的问题。看来即使要进行重构,我也必须 了解有关“ ch5-eceval-compiler.scm”的更多语义,并且如果必须的话,我 最好以不变的形式重写它。

set-car!, set-cdr! unbound in racket? 使用quotemquote。以下三个实验 引用了堆栈溢出的其他答案:

#lang sicp
#lang r5rs

指向明确定义#lang r5rs (define foo '(a b)) (set-cdr! foo '(c)) foo 的地方:

Error: struct:exn:fail:contract:variable

set-cdr!: undefined;
 cannot reference an identifier before its definition
  in module: "/usr/share/racket/pkgs/r5rs-lib/r5rs/main.rkt"
             -----------------------------------------------

这里是set-cdr!的类似失败

...
(module main scheme/base
  (require scheme/mpair
           racket/undefined
           (for-syntax scheme/base syntax/kerncase
                       "private/r5rs-trans.rkt")
           (only-in mzscheme transcript-on transcript-off))

  (provide (for-syntax syntax-rules ...
                       (rename-out [syntax-rules-only #%top]
                                   [syntax-rules-only #%app]
                                   [syntax-rules-only #%datum]))
           (rename-out
            [mcons cons]
            [mcar car]
            [mcdr cdr]
            [set-mcar! set-car!] ;; --------------------------
            [set-mcdr! set-cdr!] ;; <<<<<<<<======== LOOK HERE
            [mpair? pair?]       ;; --------------------------
            [mmap map]
            [mfor-each for-each])
           = < > <= >= max min + - * /
           abs gcd lcm exp log sin cos tan not eq?
           call-with-current-continuation make-string
           symbol->string string->symbol make-rectangular
           exact->inexact inexact->exact number->string string->number
...
#lang sicp

指向仅间接定义#lang sicp (define foo '(a b)) (set-cdr! foo '(c)) foo 的代码,但在 合适的包装:

Error: struct:exn:fail:contract:variable

set-cdr!: undefined;
 cannot reference an identifier before its definition
  in module: "/home/rebcabin/.racket/7.2/pkgs/sicp/sicp/main.rkt"
             ----------------------------------------------------

我深入研究 Implement SICP evaluator using Racket 并找到

set-cdr!

屈服

....
#lang racket

(require racket/provide         ;; --------------------------------------------
         (prefix-in r5rs: r5rs) ;; <<<<<<<<======== PULL IN SET-CDR! ETC. HERE?
         (rename-in racket [random racket:random])) ;; ------------------------

(provide (filtered-out (λ (name) (regexp-replace #px"^r5rs:" name ""))
                       (except-out (all-from-out r5rs) r5rs:#%module-begin))
         (rename-out [module-begin #%module-begin]))

(define-syntax (define+provide stx)
  (syntax-case stx ()
    [(_ (id . args) . body) #'(begin
                                (provide id)
                                (define (id . args) . body))]
    [(_ id expr) #'(begin
                     (provide id)
                     (define id expr))]))
...

此错误表示问题确实出在引用列表上。我没有 简单的方法可以将eceval中的大引用列表变成(require (only-in (combine-in rnrs/base-6 rnrs/mutable-pairs-6) set-car! set-cdr!)) (define foo '(a b)) (set-cdr! foo '(c)) foo Error: struct:exn:fail:contract set-mcdr!: contract violation expected: mpair? given: '(a b) argument position: 1st other arguments...: '(c) 。我尝试过,它非常冗长且容易出错,而且我认为代码 加载eceval扫描和列出的补丁程序,因此它使用其他列表操作。 我走南路后不得不退缩。

也许我错过了一种自动化转换的方法,一个宏,但这是一个 兔子洞较深(我的宏宏方案太旧了。)

所以我被困住了。没有简单或推荐的作品。我想要么(1)知道一个方案实现,它将运行此代码(2)我可以在球拍(3)中实现mlistmcons的某种方式(4) ),或者我只是犯了一个愚蠢的错误,其中一个人很容易修复。

2 个答案:

答案 0 :(得分:2)

我尝试过(通过直接运行racket或通过DrRacket运行它)

#lang sicp

(define foo '(a b))
(set-cdr! foo '(c))
foo

并输出(a c)

这也有效:

#lang r5rs

(define foo '(a b))
(set-cdr! foo '(c))
(display foo)

要回答有关SICP的实施问题(我目前正在维护),您正确的认为(prefix-in r5rs: r5rs)将导入set-cdr!


更新:我刚刚安装了Geiser,现在遇到的问题与您C-c C-b时遇到的问题相同。但是,C-c C-a可以正常工作。

我个人会使用racket-mode而不是Geiser。

答案 1 :(得分:0)

Mit-scheme将根据问题中提到的代码加载eceval编译器。在Ubuntu上,mit-scheme加载sudo apt-install mit-schemegeiser package of emacs通过run-mit查找信息。问题解决了。