Когда я определяю функцию внутри другой функции, я получаю сообщение об ошибке "плохое определение размещения"

Вот мой код:

 (require 'hash-table)

 (define (hash-table-get htable key)
    ((hash-inquirer equal?) htable key))

 (define (hash-table-add! htable key val)
    ((hash-associator equal?) htable key val))

 (define (hash-table-remove! htable key)
    ((hash-remover equal?) htable key))


 (define (find-max-chain)
      (define table (make-hash-table 1000)) ; works
      .
      .
      .          ; proven working code

      (define (get-chain number) (let ((chain (hash-table-get table number))) chain))

      .
      .
      .        ; more code




    max-entry)
   (find-max-chain)

Проблема в части (define (get-chain number) [...] )). Когда я определяю его и table вне (find-max-chain) в глобальном контексте, он завершается успешно, когда я его запускаю. Но когда я определяю (get-chain) внутри (find-max-chain) там, где мне это нужно, при выполнении (find-max-chain) я получаю эту ошибку от SCM:

;ERROR: "problem14-new.scm": bad placement define
; in expression: (define (get-chain! number) (let ((chain (hash-table-ge ...
; in scope:
;   (update-max! table max-chain max-entry . #@define)
;   ()  procedure find-max-chain
; defined by load: "problem14-new.scm"

;STACK TRACE
1; (#@define ((update-max! (#@lambda (entry chain) (cond ((> chai ...
2; (#@find-max-chain)
3; (#@define ((hss (#@has-suffix? #@file (#@scheme-file-suffix))) ...

Почему это?


person djhaskin987    schedule 02.08.2011    source источник


Ответы (2)


Внутри функции define разрешены только в начале функции (или функционально-подобного тела), где в любом случае они эквивалентны letrec. См. этот раздел от R5RS.

person newacct    schedule 03.08.2011
comment
Я думаю, это ответ. На самом деле, я продолжал экспериментировать и обнаружил, что код с одним оператором letrec в начале, определяющим все, наконец заработал. Спасибо! - person djhaskin987; 04.08.2011

Я не очень хорошо знаком с SCM и его сообщениями об ошибках, но мое первое предположение будет заключаться в том, что вы столкнулись с проблемой letrec vs letrec*. R5RS говорит (грубо), что должна быть возможность вычислить каждую правую часть в letrec форме, не касаясь ни одной из letrec связанных переменных; и то же ограничение справедливо для внутренних определений. (IIRC, R6RS добавил форму letrec*, которая разрешает такие ссылки.)

Например, следующее является незаконным:

(let ()
  (define x 1)
  (define y (+ 1 x))
  y)

потому что для оценки y rhs требуется значение x. Напротив, это нормально:

(let ()
  (define x 1)
  (define f (lambda () (+ 1 x)))
  (f))

То есть это не вопрос области видимости, это вопрос того, когда переменная «готова к использованию».

person Ryan Culpepper    schedule 03.08.2011