Rakuのパラメーター化された型、実行時の値をパラメーターとして使用する方法

Nov 28 2020

楽焼用にパラメータ化されたタイプをいくつか作成したいと思います。基本的に、いくつかの異なるクラスを作成したいと思います。その主な違いは、その属性の1つの値の範囲です。たとえば、クラスは建物のタイプを表しますが、3階またはその他の階数の建物ごとに異なるクラスを作成したいと思います。だからこれは私が考えることができる最高のものです:

subset Two-Tops of UInt where * <=2;
subset Three-Tops of UInt where * <=3;

role Zipi[ ::Capper ] {
    has Capper $.floor; } class Capped-at-three does Zipi[Three-Tops] {} my $capped = Capped-at-three.new( floor => 2 );
say $capped.raku;

これは、さまざまな数のフロアを処理する必要があるとすぐに明らかに非実用的です(ここグラナダでは、最大で10階あると思いますが、まあ...)。ここでの問題は、基本的にコンパイル時にサブセットの情報が必要なことです。したがって、マクロを使用しない限り(まだ実験的です)、どのような種類の変数も使用できません。では、パラメータの任意の値に対してこの種のカレーロールを定義する実用的な方法を考えることができますか?

回答

8 user0721090601 Nov 28 2020 at 15:51

実際、前に述べたように、where句で問題なく条件を使用できますが、中かっこで囲む必要があります。

role Zipi[$condition] { has $.floor is rw where {$_ ~~ $condition}
    method foo($x) { $!floor = $x } } class A does Zipi[2 < * < 5] { method bar($x) { $.floor = $x }
}

#my $a = A.new( floor => 10); # error my $a = A.new( floor => 4); # OK

#$a.foo(10); # error $a.foo(3); # OK

#$a.bar(0); # error $a.bar(4); # OK

#$a.floor = 9; # error $a.floor = 3; # OK

それはすべての割り当てタイプをカバーする必要があります

5 raiph Nov 28 2020 at 04:15

私は非常に限られたMOPチョップを持っており、以下は醜いようですが、それは機能し、正しい方向への一歩かもしれません。

私がしたこと:

  • subsetMOPを介して10,000秒のアレイを動的に構築しました。

  • 時間は、を介してコンパイル時間に構造をシフトしましたBEGIN

  • 配列の適切な要素を使用して、役割をパラメーター化しました。

my @max-floors-checkers; 
BEGIN {
  @max-floors-checkers = do for ^10_000 -> \floors {
    Metamodel::SubsetHOW.new_type: 
      refinee => UInt,
      refinement => { $^floors <= floors } } } role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
    
class Capped-at-three does BuildingCategory[ @max-floors-checkers[3] ] {}

my $capped3 = Capped-at-three.new( floors => 2 ); say $capped3.raku;                                # Capped-at-three.new(floors => 2

my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed 
3 user0721090601 Nov 28 2020 at 01:40

匿名のwhere句を使用しようとしましたが、役に立たなかったのと同様に、問題を追跡しました。where句はBUILDメソッドによって無視されているようです。句$!floorをバイパスする(経由で)直接アクセスできるためwhereか、何か別の奇妙なことが起こっNilているためかはわかりません(おそらく後者の場合、where句でパラメータ化された値を使用しようとすると、一般的にわかります)。

それでも、これは役立つエラーメッセージを表示するなど、うまく機能するはずです。

role Zipi[$condition] {
    has $.floor; submethod BUILD(:$floor, |c) {
        die "Invalid floor number."
            unless $floor ~~ $condition;
        $!floor = $floor;
    }
}

フロアが常に0 .. xであると想定できる場合、またはx .. yさらに役立つエラーメッセージを提供できる場合は、変更が簡単であることがわかります。

1 raiph Nov 29 2020 at 21:38

読者がJavaを知っているが、Rakuを知らない場合をカバーするnanswer。

Collection<String> coll = new LinkedList<String>();

楽焼のパラメータ化されたタイプ

リンクされたJavaの例は次のとおりです。

実際の型引数を使用したジェネリック型のインスタンス化は、パラメーター化された型と呼ばれます。(パラメーター化されたタイプの)例:

Collection<String> coll = new LinkedList<String>();

妥当なRakuアナログは次のとおりです。

my Positional[Str] \coll = Array[Str].new;

Positionalタイプは、パラメータ化され役割。ロールは、タイプのインターフェースおよび/または部分的な実装を指定します。RakuPositionalはJavaと十分に類似しCollectionているので、このnanswerの目的に役立ちます。

Arrayタイプは、パラメータ化されたクラス。Positionalロールに準拠するデータ構造を指定します。これはリンクリストではありませんが、このnanswerの目的には十分です。