2016-06-30 1 views
3

私の質問は、hereと尋ねられた質問と同じですが、実際には答えはありません。構造体コンストラクタのオーバーロード?

私は親構造体Aから継承している束の構造体を持っています。この構造体には、すべての子孫に対してオプションとしたい2つのフィールドがあります。以前はを使用していましたが、それはstruct-copyのようなメソッドを破るために必要なものではなく、オプションで構造体作成時にこれらのフィールドの値をオプションで指定できるようにしたいと考えています。

structのオプションの引数について他にもいくつかの質問がありますが、答えはすべてカスタムコンストラクタを定義して代わりに使用することを示唆しています。残念ながら、私はすでに正規のコンストラクタを使用している多くのコードを持っているので、私が本当に望むのは、このカスタムコンストラクタが構造体自体と同じ名前を持つことです。私がリンクしていた質問に対する答えは、私が探していたものでしたが、残念ながらREPLでは重複する定義が許されているため、REPLでしか動作しません。 REPLの外では、たとえば、(リンクされた質問への答えを実行すると)module: duplicate definition for identifier in: exn:my-appのようなエラーが出ます。

編集:重複した定義の問題は、struct idがトランスフォーマにもバインドされているためです。私はその定義が起こるのを止めたくありません。私は、コンストラクタとデフォルトのコンストラクタではない構造体のトランスフォーマの両方にバインドされた名前が必要です。

これを行う方法はありますか?既存のコードでうまくいくでしょうか?

答えて

3

私は抽象的にはるかに簡単で、より重要なのは、ビットクリーナーです解決策を考え出すしたと思う、soegaardが言及した新しい構造体のキーワードにさらに探し(それらのモジュールと必要性は私に本当に苦労していました)。私は将来の参照のためにそれを共有すると思った。繰り返しになりますが、これには夜間のラケットビルドの1つが必要です。私は6.5.0.7を使用しています。

(注:case-lambdaの使用はここでのキーワード引数の定義よりも私の好みです。)

#lang racket 

(require (for-syntax syntax/transformer)) 

(struct horse (color) 
    #:name Horse 
    #:constructor-name Horse 
    #:transparent) 

(define make-horse 
    (case-lambda 
    [() (Horse "black")] 
    [(color) (Horse color)])) 

(define-match-expander horse 
    ; match expander 
    (λ (pat) 
    (syntax-case pat() 
     [(_ more ...) #'(Horse more ...)])) 

    ; constructor 
    ; edit: changing this to use make-variable-like-transformer, 
    ; as suggested in the comments. 
    #;(syntax-id-rules() 
     [(_ args ...) (make-horse args ...)] 
     [horse Horse]) 
    (make-variable-like-transformer #'make-horse)) 

使用例:要するに

> (define black-beauty (horse)) 
> black-beauty 
(horse "black") 

> (define ginger (horse "red")) 
> ginger 
(horse "red") 

> (match black-beauty 
    [(horse color) color]) 
"black" 

> (match ginger 
    [(horse color) color]) 
"red" 

> (horse-color black-beauty) 
"black" 

> (horse-color ginger) 
"red" 

:インスタンス化、マッチング、およびアクセスのフィールドはあなただけstructを使用したい場合は、期待通りに動作するように見えます。 struct idは、構文の問題がなくても識別子として使用できます。私は実際にその部分が多くの実用的な使用を持っているとは思わないが、それはいいと思った。

+1

はるかに良い解決策! – soegaard

+1

この解決法を少し良くするために、 '(syntax-id-rules(){(args ...)(f arg ...)] [[f])'パターンは['make -variable-like-transformer'](http://docs.racket-lang.org/syntax/transformer-helpers.html#%28def._%28%28lib._syntax%2Ftransformer..rkt%29._make-variable -like-transformers%29%29)関数を使用します。あなたは '(make-variable-like-transformer# 'make-horse)'のように使うことができます。これにより、 'syntax-id-rules'フォームにある' set! 'バグも回避されます。 –

+0

ああ、クール!私はそれを知らなかった。私はそれを追加します。ありがとう! – Anonymous

2

構造体struct構造体は、構造体の名前を持つ2つのエンティティを定義します。構造体に関する情報を持つコンストラクタとトランスフォーマ・バインディング。

「重複した識別子」エラーを回避するために、#:omit-define-syntaxesを使用できます。

代わりに、サブモジュールに構造体を定義し、必要なものだけを書き出します(場合によっては識別子の名前を変更することもできます)。

#lang racket 
(struct horse (color) 
    #:constructor-name make-horse 
    #:omit-define-syntaxes 
    #:transparent) 

(define (horse #:color [color "black"]) 
    (make-horse color)) 

(horse) 
(horse #:color "red") 

出力:

(horse "black") 
(horse "red") 

EDIT

一致して機能するソリューションは、一致エキスパンダーの助けを借りて可能です。 注:#:extra-nameを使用しているため、これを動作させるにはバージョン6.5以上が必要です。

#lang racket 

(module horse racket 
    (provide (struct-out Horse) 
      make-horse) 
    (struct horse (color) 
    #:extra-name Horse 
    #:extra-constructor-name make-horse 
    #:transparent)) 

(require 'horse) 

; the custom horse constructor 
(define (my-make-horse #:color [color "black"]) 
    (make-horse color)) 

(define-match-expander horse 
    ; match expander 
    (λ (pat) 
    (syntax-case pat() 
     [(_horse more ...) 
     #'(Horse more ...)])) 
    ; constructor 
    (λ (stx) 
    (syntax-case stx() 
     [(_horse arg ...) 
     (syntax/loc stx 
     (my-make-horse arg ...))]))) 

(horse) 
(horse #:color "red") 

(match (horse #:color "blue") 
    [(horse color) color]) 

出力:

(horse "black") 
(horse "red") 
"blue" 
+1

これはコンストラクタのオーバーロードに使用できますが、変圧器を同じ名前にバインドしてマッチングする必要があるため、問題があります。だから私はオーバーロードされたコンストラクタとトランスフォーマーの両方を同じ名前にバインドすることができるようにしたい。 – Anonymous

+1

私は一致して動作するソリューションを追加しました。 – soegaard

+0

ありがとう、これは有望そうです!不思議なことに、Racket 6.5を持っていても、私は#:extra-nameに問題があります。私はこのことを覚えておいて、ある時点で問題を解決することができます。 #:extra-nameにあるドキュメンテーションから、Horseは構造体情報にのみバインドされているので、Horse-colorではなく、Horse-colorをエクスポートするような構造になっています。あれは正しいですか? – Anonymous