【问题标题】:Parametrized types in Raku, how to use run time values as parametersRoku 中的参数化类型,如何使用运行时值作为参数
【发布时间】:2021-03-10 11:58:47
【问题描述】:

我想为 Raku 创建一些 parametrized types;基本上,我想创建一些不同的类,它们的主要区别在于其属性之一的值范围;例如,类代表建筑物的类型,我想为具有 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 个楼层,但是……)。这里的问题基本上是你需要在编译时获得子集的信息,所以除非你使用macros(仍然是实验性的),否则你无法使用任何类型的变量。那么你能想出一种实用的方法来为参数的任何值定义这种curried roles吗?

【问题讨论】:

    标签: roles raku


    【解决方案1】:

    我尝试使用匿名 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 .. xx .. y,您会看到修改是多么容易,并且可以提供更有用的错误消息。

    【讨论】:

    • 这里的问题是你不能保证$.floor在运行时会继续满足约束;你需要额外的检查。但这是一个很好的解决方案,谢谢。
    【解决方案2】:

    我的 MOP 印章非常有限,以下看起来很难看,但它确实有效,并且可能是朝着正确方向迈出的一步。

    我做了什么:

    • 通过 MOP 动态构造一个包含 10,000 个subsets 的数组。

    • 时间通过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 
    

    【讨论】:

    • 虽然我想出了一个更简单的方法来完成手头的特定任务....这太不可思议了。从来没有想过要创建这么多这样的子集。
    • MOP 是Peter Parker's principle 的一侧。当然,可怕的大规模毁灭性子集(†)昨晚在我的噩梦中徘徊(现在可能会传播到那些阅读上述内容的人)。但我不感到痛苦或恐惧或责任,并且拒绝停止! .oO(我敢希望a superhero like @user0721090601 will show we can have power and beauty?
    • 只要我们去MOP,为什么不一路走?理论上,我们可以创建一个运行时函数来动态创建角色。无论如何我们都需要它,因为类也必须动态创建,否则我们最终会遇到几乎相同的问题。在编译期间,我们需要知道我们需要的楼层数。
    • @jjmerelo I will not stop! :) 由于多种原因,我对您所追求的感到困惑。我将在此评论中提到两个。首先是XY。您的 Q 的序言基于一个简单的 Java 示例的链接,其中有简单的 Raku 等价物。但是您的示例非常复杂。在我上面的回答中,我决定直接解决您的复杂示例,忽略 XY 的感觉。其次是您上面的评论。您是否忽略了BEGIN?更重要的是,您是指编译时间还是编译阶段运行时间还是运行阶段
    【解决方案3】:

    实际上,与我之前所说的不同,您可以在 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
    

    这应该涵盖所有的分配类型

    【讨论】:

    • 这不需要高魔法,很抱歉,@raiph,我选择了它。谢谢!
    • .oO(我很高兴@jj 得到并接受了这个解决方案,而不是我的!)什么?!?谁说的?我在使用* 时遇到了与where 子句相同的问题,但发现它使用大括号和~~ 有效。但我没有意识到这就是您所说的“我尝试使用匿名where 子句”的意思。也许您阅读了我的答案并看到了该选项并启发了上述内容?在这种情况下,我的抱负“朝着正确的方向迈出一步”适用,反过来,它可能会激励我们所有人保持领先于可怕的蹒跚者,并知道我们在一起,并分享渴望传播我们所拥有的...... ;)
    • @raiph:ps,看看 reddit — 很想对我的帖子有一些反馈,因为 CLDR(默认重视您的输入/观察)
    • 嘿。我刚刚在那里发表了评论,然后访问了这里并第一次看到了您的评论。也许这是一种僵尸力量,我没有意识到我已经读懂了你的想法?
    • @raiph 我现在对此不太确定。归根结底,它需要运行时常量。它更灵活一些。所以会再看看你的答案,也许会再次切换。
    【解决方案4】:

    一个回答读者知道 Java 但不知道 Raku 的案例。

    Collection&lt;String&gt; coll = new LinkedList&lt;String&gt;();

    parametrized types 代表乐

    链接的 Java 示例是:

    具有实际类型参数的泛型类型的实例化称为参数化类型。示例(参数化类型):

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

    一个合理的 Raku 类比是:

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

    Positional 类型是可参数化的role。角色指定类型的接口和/或部分实现。我相信 Raku 的 Positional 与 Java 的 Collection 非常相似,因此它用于本 nanswer 的目的。

    Array 类型是可参数化的class。它指定了一个遵循Positional 角色的数据结构。它不是一个链接列表,但足以满足此 nanswer 的目的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-17
      相关资源
      最近更新 更多