4

私はこれを作成しました:

(define-syntax (with-hash stx)
  (syntax-parse stx
    [(_ obj:id ((~or key:id [new-key:id hash-key:id]) ...) body:expr ...+)
     #'(let ([key (hash-ref obj 'key)] ...
             [new-key (hash-ref obj 'hash-key)] ...)
         (begin body ...))]))

私がこれを行うことができるように:

  (require rackunit)
  (define h (hash 'id 1 'name "scott"))
  (with-hash h (id [new-name name])
    (check-equal? id 1)
    (check-equal? new-name "scott"))

クライアントが呼び出しでハッシュ キーを指定せずに、すべてのハッシュ キーをローカルで自動的にバインドする代替パターンを追加するにはどうすればよいですか?

すなわち:

(define h (hash 'id 1 'name "scott"))
(with-hash h
  (check-equal? id 1)
  (check-equal? name "scott"))

トランスフォーマーの名前を変更する必要があると思われますが、ランタイム ハッシュに基づいて、構文パラメーターを宣言し、それらの名前を動的に変更できますか?

また、次のようなことが正しい軌道に乗っているのではないかと思いました。

(define-syntax (with-hash stx)
  (syntax-parse stx
    [(_ obj:id (key:id ...) body:expr ...+)
     #'(let ([key (hash-ref obj 'key)] ...)
         (begin body ...))]
    [(_ obj:id body:expr ...+)
     #'(with-hash obj (id title) body ...)]))

ここで、マクロを思い出して、バインドするデータムを解析しますが、その場合、マクロが別の方法で機能しても、id 変数と title 変数はバインドされません。

明らかに、私の理解には何かが欠けています。

どんな洞察も高く評価されます。

ありがとう。

4

3 に答える 3

1

あなたは本当にできません。変数のスコープは静的プロパティであり、ハッシュのキーは動的プロパティであるため、どのソリューションも間違っています。しかし、あなたが尋ねたので、あなたが求めているものと漠然と似ている2つの間違った解決策があります.

できることの 1 つは、 を使用することですeval。ただし、呼び出すevalと、ローカル変数が失われます。ドキュメントを参照してください。おそらく自分でコードを作成できます。

#%topこれは、バインドされていない (または「トップレベル環境によってバインドされている」) 変数への変数参照を暗黙的にラップする構文です。ただし、これは、ローカルまたはモジュール レベルのバインドが既にあるキーをシャドーできないwith-hashことを意味します。とにかく、コードは次のようになります。

(define-syntax (with-hash stx)
  (syntax-case stx ()
    [(with-hash h . body)
     (with-syntax ([#%top (datum->syntax stx '#%top)])
       #'(let-syntax ([#%top
                       (syntax-rules ()
                         [(#%top . x)
                          (hash-ref h 'x)])])
           (begin . body)))]))
于 2013-04-21T05:28:48.383 に答える
1

Dang、Ryan は、私が答えを見つけようとしているときに応答しました :) とにかく eval を使用した解決策を次に示しますが、他の人がすでに表明しているのと同じ警告があります。

#lang racket

(require (for-syntax syntax/parse))

(define-syntax (with-hash stx)
  (syntax-parse stx 
   [(_ h:expr body:expr ...+)
    #'(begin
        (define-namespace-anchor a)
        (let ([keys (hash-keys h)])
          (define (mk-bind k) `[,k (hash-ref h (quote ,k))])
          (eval 
           `(let ,(map mk-bind keys) 
              ,@(quote (body ...))) 
           (namespace-anchor->namespace a))))]))

(require rackunit)
(define h (hash 'id 1 'name "scott"))
(with-hash h
  (check-equal? id 1)
  (check-equal? name "scott"))

編集:

別の方法として、特定の方法でのみ使用することがわかっている場合は、このようなもので偽造することができます.

#lang racket

(require (for-syntax syntax/parse))

(define-syntax (with-hash stx)
  (syntax-parse stx #:datum-literals (check-equal?)
    [(_ h:expr (check-equal? key:id val:expr) ...)
     #'(let ([keys (hash-keys h)])
         (check-true (hash-has-key? h (quote key))) ...
         (check-equal? (hash-ref h (quote key)) val) ...)]))

(require rackunit)
(define h (hash 'id 1 'name "scott"))
(with-hash h
  (check-equal? id 1)
  (check-equal? name "scott"))
于 2013-04-21T05:58:50.280 に答える
1

別の方向に進み、識別子の提供に固執することをお勧めします。Scheme プログラムで識別子が作成/評価環境に追加されると、常に少し疑わしいものになります。はい、それは許可されており、安全に行うことができますが、何が、いつ、どこで拘束されているかについての理解を混乱させます。

代わりに、あなたwith-hashのフィールドへのアクセスを許可するバインディング構造として考えることをお勧めしますhash。次のように使用します。

(with-hash h ((the-id 'id) (the-name 'name)) ...)

または、デフォルト名を使用して、

(with-hash h (id name) ...)

次のように実装されます。

(define-syntax with-hash
  (syntax-rules ()
    ((_ "gen" hash ((fname fkey) ...) body ...)
     (let ((obj hash))
       (let ((fname (hash-ref obj 'fkey)) ...)
         body ...))))
    ...
    ))
于 2013-04-20T20:55:48.467 に答える