8

興味深い問題に遭遇したとき、私は D の動的型付けライブラリを実装していました。

現在、dynamic()オブジェクトの動的バージョンを返す関数の作成に成功しています。

例えば:

import std.stdio, std.dynamic.core;

class Foo
{
    string bar(string a) { return a ~ "OMG"; }
    int opUnary(string s)() if (s == "-") { return 0; }
}

void main(string[] argv)
{
    Dynamic d = dynamic(new Foo());
    Dynamic result = d.bar("hi");
    writeln(result);  // Uh-oh
}

私が遭遇した問題は、コンパイル時のリフレクションをwriteln使用して を処理する方法を見つけようとするという事実です。result

それが最初に試みることは何ですか? isInputRange!(typeof(result))

問題は、それがtrueを返すことです! なんで?実行時にそうでないことを証明できない限り、必要なすべてのメンバーが存在すると想定する必要があるためです。これでは遅すぎます。frontそのため、プログラムは、popFront、およびemptyonを呼び出そうとresultし、プログラムをクラッシュさせます。

これを修正する方法が思いつきません。誰にもアイデアはありますか?

4

5 に答える 5

2

テンプレートと動的型付けという 2 つの根本的に異なる概念を連携させようとしています。テンプレートは静的型付けに大きく依存しており、 isInputRange は型が持つ属性またはメソッドをチェックすることで機能します。動的型は、コンパイル時にすべての属性またはメソッドを持つものとして扱われます。したがって、すべての静的ダックタイピング インターフェイスを満たすものとして扱われます。したがって、静的に型付けされた環境で Dynamic を機能させるには、いくつかの場所でより多くの静的情報を提供する必要があります。

私が見ることができるいくつかの解決策:

  1. 頻繁に使用される関数に対して独自の動的に型付けされた実装を提供します。あなたが抱えている問題全体は、動的型で静的型付けを想定する汎用関数を使用しようとしているという事実によって引き起こされます。

  2. 明示的にcharの範囲を動的にし、基になるデータの文字列への変換を自分で処理します。( isInputRange の問題が存在しない場合は、とにかくカスタムの toString メソッドが必要です。そうしないと、結果が再び動的タイプになるためです)。これにより、おそらく writeln(d); が作成されます。仕事。

  3. さまざまなテンプレート化された関数に動的な型を渡すことができる dynamic のラッパーを提供します。(これらは静的インターフェースを示し、すべての呼び出しを動的に転送します)。

例えば:

Dynamic d;
// wrap d to turn it into a compile-time input range (but NOT eg a forward range)
Dynamic d2=dynamic(map!q{a*2}(dynInputRange(d))); 
// profit

4 . メンバー テンプレートを動的に追加します。これにより、一部のメンバー関数名を静的に無効にすることができます。

例えば:

static assert(!isForwardRange!(typeof(d.without!"save")));
于 2011-08-22T19:14:26.380 に答える
1

isInputRange のオーバーロードを提供していただけますか? このようなもの (isInputRange の実​​装を見ていないことに注意してください):

template isInputRange(T : Dynamic) {
    enum isInputRange = false;
}

これが dynamic.core によって提供される場合、このオーバーロードは std lib の前に選択する必要があると思います。

于 2011-08-18T16:39:04.423 に答える
1

動的型付けに必要なすべてを実装する whichを使用することの何が問題なのですかstd.variant(かなりの構文糖衣とともに)

于 2011-08-18T07:51:41.220 に答える
0

あなたが言ったように、一般的なケースでは、ダイナミックはコンパイル時にメソッドルックアップを受け入れる必要があります。isInputRange 述語が true に評価されるのを防ぐことができると仮定すると、入力範囲から Dynamic を作成しようとすると、間違ったコードが生成されます。

少なくとも一般的な方法では、これは修正可能ではないと思います。この特定のケースで私が考えることができる最善の解決策は、Dynamic が独自のバージョンの toString を提供し、writeln が inputRange の特殊化よりもそれを好むことです。現時点では、少なくとも構造体に対しては writeln はこれを行わないと思いますが、おそらくそうすべきです。

もう 1 つの妥協点は、opDispatch 制約で popFront などのいくつかのメソッドを許可しないことです。代わりに、Dynamic は、これらの特殊なケースにアクセスするために opIndex またはメンバー オブジェクトを提供します。特殊なケースはまれであり、それらを使用すると明らかなコンパイラ エラーが発生するため、これは思ったほど悪くはないかもしれません。

Dynamic のこの種のメソッド解決を救済する最善の方法は、writeln を修正し、Dynamic がすべてのテンプレート化されたコードで機能しないことを受け入れることだと思います。

于 2011-08-22T18:04:25.370 に答える
0

std.variant を調べましたか?

import std.stdio, std.variant;

class Foo {
    string Bar(string a) {
        return a ~ " are Cool!";
    }
}

void main() {
    Variant foo = new Foo();
    Variant result = foo.peek!Foo.Bar("Variants");

    writeln(result); // Variants are Cool!
}

http://www.d-programming-language.org/phobos/std_variant.html

于 2011-10-24T18:05:38.560 に答える