8

私は Racket にモジュール meta-language を書き込もうとしてmylangいます。これは、次のように、変更された本体を渡す第 2 言語を受け入れます。

(module foo mylang typed/racket body)

次と同等です。

(module foo typed/racket transformed-body)

もちろん、そのtyped/racket部分は他のモジュール言語に置き換えることができます。

本体はそのままの簡易版にしてみました。コマンドラインでは問題なく動作しますが、DrRacket で実行すると次のエラーが発生します。

/usr/share/racket/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:479:30: require: namespace mismatch;
 reference to a module that is not available
  reference phase: 1
  referenced module: "/usr/share/racket/pkgs/typed-racket-lib/typed-racket/env/env-req.rkt"
  referenced phase level: 0 in: add-mod!

コード全体は次のとおりです。

#lang racket

(module mylang racket
  (provide (rename-out [-#%module-begin #%module-begin]))
  (require (for-syntax syntax/strip-context))
  (define-syntax (-#%module-begin stx)
    (syntax-case stx ()
      [(_ lng . rest)
       (let ([lng-sym (syntax-e #'lng)])
         (namespace-require `(for-meta -1 ,lng-sym))
         (with-syntax ([mb (namespace-symbol->identifier '#%module-begin)])
           #`(mb . #,(replace-context #'mb #'rest))))])))

(module foo (submod ".." mylang) typed/racket/base
  (ann (+ 1) Number))

(require 'foo)

要件(つまり、避けたいソリューション):

  • (require (only-in typed/racket))モジュール内にa を追加するとこの作業が行われますが、 at alについて知る必要がないmylang一般的な解決策に興味があります(つまり、誰かが新しい言語を追加した場合、箱から出してそれを使用する必要があります)。mylangtyped/racketfoomylang
  • また、ここで行われているように、サブモジュールを宣言してすぐrequireに再実行するトリックには興味がありません。これは、実際のモジュールへのパスが変更されるためです (たとえば、特別な動作が失われるため) 。providemaintest

    サブモジュールがより多くの回数アクセスおよび/またはインスタンス化されるため、コンパイル時も遅くなります(これは を書くことで確認でき(begin-for-syntax (displayln 'here))、大規模なプログラムに顕著な影響を与えtyped/racketます.

  • DrRacket の矢印が委譲先言語によって提供されるビルトインで機能する場合、annボーナスポイント。+Numbertyped/racket/base

4

1 に答える 1

4

あなたができることの1つは、要件に違反していないと思いますが、それをモジュールに入れ、そのモジュールを完全に展開して#%plain-module-beginから、requireを挿入することです。

#lang racket

(module mylang racket
  (provide (rename-out [-#%module-begin #%module-begin]))
  (define-syntax (-#%module-begin stx)
    (syntax-case stx ()
      [(_ lng . rest)
       (with-syntax ([#%module-begin (datum->syntax #f '#%module-begin)])
         ;; put the code in a module form, and fully expand that module
         (define mod-stx
           (local-expand
            #'(module ignored lng (#%module-begin . rest))
            'top-level
            (list)))
         ;; pattern-match on the #%plain-module-begin form to insert a require
         (syntax-case mod-stx (module #%plain-module-begin)
           [(module _ lng (#%plain-module-begin . mod-body))
            #'(#%plain-module-begin
                (#%require lng)
                .
                mod-body)]))])))

;; Yay the check syntax arrows work!
(module foo (submod ".." mylang) typed/racket/base
  (ann (+ 1) Number))

(require 'foo)

体を何らかの方法で変形させたい場合は、拡張の前または後に行うことができます。

(#%require lng)利用可能なコンテキストでモジュール本体を展開するlngだけでは不十分なため、extra を挿入するためのパターン マッチングが必要です。コードをフォームmod-bodyから戻すmoduleということは、バインディングが を参照することを意味しますがlnglng実行時には使用できなくなります。それがrequire: namespace mismatch; reference to a module that is not availableないとエラーが発生するのはそのためです。そのため、展開後に追加する必要があります。

コメントから更新

ただし、@GeorgesDupéron がコメントで指摘したように、これにより別の問題が発生します。がlng識別子xを提供し、それが使用されるモジュールが別xの をインポートする場合、あってはならない場所でインポートの競合が発生します。Require 行は、モジュール言語に関して「ネストされたスコープ」にある必要があるため、xここのように識別子を隠すことができます。

@GeorgesDupéron は、ラケット ユーザー リストのこのメールで、 onを使用(make-syntax-introducer)mod-bodyてネストされたスコープを生成することで、この問題の解決策を見つけました。

(module mylang racket
  (provide (rename-out [-#%module-begin #%module-begin]))
  (define-syntax (-#%module-begin stx)
    (syntax-case stx ()
      [(_ lng . rest)
       (with-syntax ([#%module-begin (datum->syntax #f '#%module-begin)])
         ;; put the code in a module form, and fully expand that module
         (define mod-stx
           (local-expand
            #'(module ignored lng (#%module-begin . rest))
            'top-level
            (list)))
         ;; pattern-match on the #%plain-module-begin form to insert a require
         (syntax-case mod-stx (module #%plain-module-begin)
           [(module _ lng (#%plain-module-begin . mod-body))
            #`(#%plain-module-begin
                (#%require lng)
                .
                #,((make-syntax-introducer) #'mod-body))]))])))
于 2016-06-25T19:15:46.563 に答える