Как вы относитесь к затененной переменной верхнего уровня? - PullRequest
0 голосов
/ 15 сентября 2018
#lang racket

(define (shadowed x)
  'the-normal-result)

(define (f . args)
  (define (shadowed x)
    (cons 'local-extra (top-level-shadowed x)))
  (for/list ([arg args])
    (shadowed arg))) ;I want to be careful that I don't accidentally call the top-level shadowed func here

Как показано выше, иногда я хочу локально скрыть функцию верхнего уровня, потому что вместо этого я хочу вызвать вариант, а вариант должен вызвать функцию верхнего уровня.

Опыт показывает, что присвоение локальному варианту имени варианта, например shadow^, приводит к ошибкам, потому что я случайно вызываю функцию верхнего уровня из внутренней области видимости.

Как я могу "выпрыгнуть" из внутренней области или как-то квалифицировать идентификатор для ссылки на его привязку на верхнем уровне или в явно указанном модуле?

Обновление

Я нашел то, что выглядит многообещающе: #% top . Однако, когда я попробовал это, вот что я получил:

> (define (f x) (list 'top x))
> (define (g x)
    (define (f x) (cons 'inner ((#%top . 'f) x)))
    (cons 'here (f x)))
. #%top: not an identifier in: (quote f)
> (define (g x)
    (define (f x) (cons 'inner ((#%top . f) x)))
    (cons 'here (f x)))
?: free identifier found in linklet

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Простейший случай: если переменная верхнего уровня происходит от другого модуля

Если переменная верхнего уровня импортируется из другого модуля, как в этой программе:

; other-module.rkt
#lang racket
(provide shadowed)
(define (shadowed x)
  'the-normal-result)

; main-module.rkt
#lang racket
(require "other-module.rkt")

(define (f . args)
  (define (shadowed x)
    ; I want to use the shadowed identifier from the other module
    (cons 'local-extra (shadowed-from-other-module x)))
  (for/list ([arg args])
    (shadowed arg)))

Вы можете использовать local-require следующим образом:

(define (f . args)
  (define (shadowed x)
    (local-require "other-module.rkt")
    (cons 'local-extra (shadowed x)))
  (for/list ([arg args])
    (shadowed arg)))

Более сложный случай, с использованием операций установки области действия для ссылки на другие области действия

Вы можетесоздайте макросы declare-scope и in-scope, которые будут использоваться следующим образом:

#lang racket
(declare-scope top)
(define x "outer")
(let ()
  (define x "inner")
  (in-scope top x))
;"outer"

Этот API имеет то преимущество, что он все еще работает, если вы оборачиваете все в еще большую область:

(declare-scope top)
(define x "outer")

(let ()
  (declare-scope mid)
  (define x "middle")

  (let ()
    (define x "inner")
    (in-scope mid x)))
;"middle"

В контексте вашего кода это будет выглядеть следующим образом:

(declare-scope top)
(define (shadowed x)
  'the-normal-result)

(define (f . args)
  (define (shadowed x)
    (cons 'local-extra ((in-scope top shadowed) x)))
  (for/list ([arg args])
    (shadowed arg)))

Эти макросы могут быть определены с помощью операций с областью действия (в частности, make-syntax-delta-introducer) вот так:

#lang racket

(require syntax/parse/define)

(define-syntax-parser declare-scope
  [(_ name:id)
   #:with stx this-syntax
   ;; This saves the syntax object at compile-time, so that in-scope
   ;; can reference it later.
   #'(define-syntax name (quote-syntax stx))])

(define-syntax-parser in-scope
  #:track-literals
  [(_ scope exp/def)
   ;; This gets scope-stx, the syntax object that was saved when the
   ;; scope was declared.
   #:declare scope (static syntax? "scope")
   (define scope-stx (syntax-local-introduce (attribute scope.value)))
   ;; This delta introducer has the scopes that are:
   ;;  - in exp/def
   ;;  - but not in scope-stx
   (define delta (make-syntax-delta-introducer #'exp/def scope-stx))
   ;; This removes the scopes that are in delta.
   (delta #'exp/def 'remove)])
0 голосов
/ 16 сентября 2018

Это то, что вы хотите?

#lang racket

(define (shadowed x)
  'the-normal-result)

(define (f . args)
  (let ([top-level-shadowed shadowed])
    (define (shadowed x)
      (cons 'local-extra (top-level-shadowed x)))
    (for/list ([arg args])
      (shadowed arg)))) ;I want to be careful that I don't accidentally call the top-level shadowed func here

(f 3 4 5)

Я допускаю, что это один из тех редких случаев, когда универсальный сдвиг «определяй, а не позволяй» усложняет жизнь.

...