SICP Ch5 eceval компилятор в Racket: set-cdr! в котируемый список (не дупл) - PullRequest
2 голосов
/ 24 марта 2019

Это не дубликат set-car !, set-cdr! несвязанный в ракетке? или из Реализация SICP-оценщика с использованием Racket или из Как установить модуль пакета sicp в ракетку? , а скорее последующий вопрос, потому что предлагаемые в нем решения не работать на меня. Во-первых, необходимо: раздел 5.5.5 SICP , компилятор плюс оценщик явного управления ( код здесь в "ch5-eceval-compiler.scm" ), полностью зависит от set-car! и set-cdr! в явных кавычках. я хотел бы скопировать и изменить этот код без полной перезаписи неизменная форма. Я также принял бы ссылку на реализацию схемы, которая может запустить код "из коробки" или с минимальной, простой адаптацией, схема, которая имеет set-car! и set-cdr! или некоторые работать вокруг. Ни хитрость, ни рэкет не дают мне времени на запуск этого кода.

EDIT : схема будет загружать компилятор eceval. Я оставляю вопрос для тех, кто хотел бы, чтобы это было в ракетке (я бы предпочел, например).

Вот более глубокое объяснение, включая то, что я исследовал и испытал, и как я диагностировал цитируемый список как самую глубокую проблему. Когда я конвертировал цитируемый список в mquoted гнездо mlists, код сломался намного хуже пути и кроличья нора стали намного глубже. Я должен был вернуться через пару часы тонкой операции на головном мозге, которая не удалась.

Вот MVE типа структуры, на которую опирается раздел 5.5.5. Это мало, но конструктивно похоже на реальную вещь:

(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! недоступны в #lang racket, и я не думаю, что они в либо guile (по крайней мере, guile отказался загружать "ch5-eceval-compiler.scm", выдает ошибку изменчивости, на которую я копать не глубже).

Одно решение, предложенное в set-car !, set-cdr! unbound в ракетке? есть переписать код с помощью mcons, mcar, mlist и т. д. в соответствии с (require compatibility/mlist) (require rnrs/mutable-pairs-6). Те совместимость пакеты не заменяют quote, поэтому я попытался написать собственный mquote. я потратил пару часов на такой рефакторинг, но упражнений не было сходятся, просто уходят все глубже и глубже в кроличью нору и заканчивают тем, что еще более глубокие проблемы. Кажется, чтобы проводить даже рефакторинг, я должен понять больше семантики о "ch5-eceval-compiler.scm", и если я должен, я может также переписать его в неизменном виде.

Более простые решения, предложенные в set-car !, set-cdr! несвязанный в ракетке? должны использовать #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"
             ----------------------------------------------------

указывает на код, который только косвенно определяет 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))]))
...

Я копаю глубже Реализация SICP-оценщика с использованием Racket и найти

(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 в mlist или цепочку mcons. Я попробовал это, и это очень многословно и подвержено ошибкам, плюс я думаю, что код который загружает eceval, просматривает и исправляет этот список, поэтому он использует другие операции со списком. Мне пришлось вернуться после неудачного пути на юг.

Возможно, я упустил какой-то способ автоматизировать преобразование, макрос, но этоболее глубокая кроличья нора (моя схема макрофу слишком старая).

Так что я застрял. Ничего легкого или рекомендуемого не работает. Я хотел бы (1) знать реализацию схемы, которая будет запускать этот код (2), каким-то образом я могу реализовать set-car! и set-cdr! в racket (3), какой-то другой способ обойти (4), или, может быть, я только что совершил глупую ошибку, которую один из вас, добрых людей, легко исправит.

Ответы [ 2 ]

2 голосов
/ 25 марта 2019

Я попытался (либо запустив 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 вместо Гейзера.

0 голосов
/ 24 марта 2019

Mit-схема загрузит компилятор eceval из выпадающего кода, упомянутого в вопросе. В Ubuntu mit-схема загружается с sudo apt-install mit-scheme. Пакет гейзеров emacs находит через run-mit. Проблема решена.

...