我有一个模块AttrX::Mooish
,该模块实现了Moo / Moose框架的某些属性功能(惰性,触发器等)。我还希望该模块对最终用户尽可能透明,这意味着支持私有和公共属性。它通过用Proxy
替换属性的容器并将其值存储在外部存储器中来工作。这也意味着Perl6所做的所有类型检查和强制执行现在是我的责任。我的目标是尽可能模仿默认行为。即对于最终用户:
has MyClass @foo is mooish(...);
必须与不应用特征时的工作方式相同。不幸的是,类型操纵的主题在语言核心中是如此复杂且统一,以至于我解决的问题越多,事后得到的问题也越多。例如:
my Str @a = <a b c>; my Str @b = [1,2,3]
Type check failed in assignment to @b; expected Str but got Int (1)
符合预期。
my Str @a; say @a.WHAT
(Array[Str])
好的。
my Array[Str] $a = ["a", "b", "c"];
Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])
好吧...
my Array[Str] $a = <a b c>;
Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))
甚至没有将List
强制为Array
!
难怪我特质代码中的最后一个类型检查行:
$coerced-value ~~ $attr.type
尽管在变量/属性分配中使用了相同的值/类型,但这里和那里仍然可以正常工作。
我有一个问题,没有希望得到任何肯定的答案:赋值运算符使用单个入口点来执行所有强制/类型检查吗?理想情况下,我会简单地:
$value = coerce($value, $type);
check-type($value, :type($attr.type), :name($attr.name))
我试图追溯语法,但还没有足够的业余时间来完成此工作。此外,大部分是nqp,我不知道,也无法真正理解。
但是,由于不太可能存在这样的切入点,因此我想请教与该领域有关的任何建议。例如,例如,#perl6上的SmokeMachine为我提供了一个使用.^parents
方法获取参数化类型的基本类型的好主意。
到目前为止,最大的问题在于:
of
方法并测试其输出。不幸的是,如果一个类提供FALLBACK
,则将产生非常不清楚的错误消息(关于AUTOGEN的错误消息)。 :no_fallback
是可取的,但是确定类型和子集类型具有自己的find_method
,它不支持命名参数,最后我会收到另一条错误消息。$!coerce-type
方法中的prepare类型相关属性(compose
)应用于Attribute
对象(实际上是在其中声明了属性),我稍后会在运行时统一。猜测与作曲时间有关的事物。但要确定这里是否没有遗漏。$value ~~ $type
更好的类型检查方法?答案 0 :(得分:3)
2019更新,我在写完此答案后不久即删除了该答案。这是一个答案。它没有直接解决问题中提出的大多数问题。在哪里,我不得不说的非常模糊。但是我只是有理由对其进行审查,因此决定暂时最好将其恢复(进行了一些编辑以提高我在其中看到的有用性)。也许Vadim只会删除整个问题,但我想也许它是一个有用的例子,表明对于像Vadim和我自己这样的不熟悉P6元编程内胆的人来说,会是什么样子。希望未来几年会出现真正的答案。
(这不是一个答案,甚至没有结束。这只是对您的问题的探索性评论。它不完全符合评论的要求;完全不属于SO。但是Perl的人不会以“错误”的方式做事,而且我们并不总是像更广泛的社区所说的那样那样写问题或答案。这仅仅是做“错”或至少做“错”的典范。)
对我有帮助的一件事(也许还有一些没有在您闲逛的地方闲逛的人,所以不知道是什么驱动了您)将对我有所帮助。为了表达我的第一条评论:
我有一个模块AttrX :: Mooish
The Mooish module's Description说:“该模块旨在提供Moo / Moose所缺少的某些功能。目前,它通过附带的方法实现了懒惰。但是将来还会有更多。”
我无法从中得知您的问题,而这是促使您执行此操作的原因。让我问一下您的动机是否符合以下一种或所有某些人为的可能性:
如果您今年要在P6中编写代码,则今年需要此功能;
即使您需要花费一年的时间,您仍希望将此功能引入P6;
您想在今年最多挑战一次挑战来学习P6;
您想为在2019年建立P6做出贡献,并考虑在今年提供像P6 Moo这样的纯材料,这对于实现这一目标来说是一件大事;
上述内容的某种组合,可能具有不同的计时参数或其他动机。
阐明您的动机的评论可能有助于直接回答您的问题。至少会很有趣。 :)
实现了Moo / Moose框架的某些属性功能(惰性,触发器等)。
您是否尝试过直接通过Inline :: Perl5使用Moo?我意识到您可能对此最终解决方案并不感兴趣,但是对于Perl 6社区和 Perl 5社区和来说,这似乎是一个非常有用的练习。整个Perl社区和,无论您想去哪里玩。
或者,也许同等甚至更有趣,Moxie。 Moxie的自述文件说它有(实验)惰性。我不知道触发器。我可以看到Moxie成为P6和P5在未来十年内可以实现强大统一的重要基础。就我而言,这个角度可能很有趣。然后,您自然会将Stevan,Stefan和您自己召集在一起,这可能会在未来几年产生有趣的分拆效果。
我本以为走这条路将带您穿越与现在所经过的相同区域,但产生的影响要大得多,而仍然带您进入纯Perl 6 Mooish或Sixie或其他任何产品。
反正,值得深思。
我还希望该模块对最终用户尽可能透明,这意味着同时支持私有和公共属性。
(Moxie特别指出了其处理私有和公共属性的方法。)
通过使用代理替换属性的容器来工作
Aiui代理的现有实现遭受重复调用的困扰。因此,读或写可能会发生几次,而您可能只希望一次。也许现在已经解决了,但是近年来肯定有一个意外的缺点。
Perl6所做的所有类型检查和强制执行现在是我的责任。
是代理方法的不良副作用,还是您需要参与该部分,所以代理方法只是使您更轻松地完成您需要做的事情?
>我的目标是尽可能模仿默认行为。
原谅我再次听起来很消极,但这听起来太可怕了,除非您的目标只是学习P6,并且您打算放弃最终结果。
不幸的是,类型操纵的主题在语言核心中是如此复杂和统一,以至于我解决的问题越多,事后得到的问题就越多。
这只会使一切听起来比我想像的还要糟糕。再说一次,也许您正在深陷兔子洞,并建议您从兔子洞中爬出,回到阳光下,将自己除尘,然后朝另一个方向前进?
例如:
my Array[Str] $a = ["a", "b", "c"];
Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])
在P6中,对于标量分配,这完全是粗暴的行为。
P6类型主要是标称,由类型名称驱动。
右侧对象的类型名称为Array
。
左侧类型约束的名称为Array[Str]
。
P6拒绝对值(Array
)进行标量(em)标定(一件事),该值名义上比变量的约束({{1 }},因为一个Array[Str]
值可能与Array
不兼容。
相反,列表分配有效:
Array[Str]
这次my Str @a = ["a", "b", "c"];
进行列表分配,即分别将右边的元素的每个分配给左边的单个=
-其中{{1 }}具有类型Scalar
的约束-每个标量分配都通过单独的标量类型检查,确定它是Scalar
。
返回另一个标量分配示例:
Str
甚至没有将列表强制转换为数组!
这打破了P6的思考范围。
Str
比my Array[Str] $a = <a b c>;
Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))
窄,所以现在您双重失败了。
同样,Array
有效。
难怪尽管变量/属性分配中使用的值/类型相同,但我的特征码
List
中的最后一个类型检查行还是到处失败。
在写这篇文章时,我太累了,无法深入研究那里发生的事情。也许您从我刚刚写的书中得到了“啊哈”。我计划明天再看一遍。
我有一个问题,没有希望得到任何肯定的答案:赋值运算符是否使用一个入口点来执行所有强制/类型检查?
好吧,我认为有两件事发生。
首先,在标量分配上进行类型检查。列表(或数组)分配上下文中的my Str @a = <a b c>;
变成对接收复合容器的元素进行迭代,并一次一次检查一个$coerced-value ~~ $attr.type
的类型。
第二,如您所见,类型检查胆量似乎是临时的。
理想情况下,我会简单地:
=
关键是Scalar
是标量还是合成。
我试图追溯语法,但还没有足够的业余时间来完成此工作。此外,大部分是nqp,我不知道,也无法真正理解。
它几乎完全是P6语言的一个简单子集,因此应该很容易,但是,是的,我通常觉得它有些野蛮。
要检查类型是否已参数化,我不能使用单个角色或类进行匹配。
我认为您需要的是在类型的元对象上调用方法,例如$value = coerce($value, $type);
check-type($value, :type($attr.type), :name($attr.name))
之类。嗯...结帐P6 archetypes(也许还有nqp archetypes)。
(不过,我再次怀疑,从代理服务器开始,从整个方法出发,您将远离杂草。而且,我认为您首先尝试通过IP5使用Moxie或Moo的途径会产生巨大的价值,哪里有东西。)
如果在我的trait角色的compose方法中将准备类型相关的属性($!coerce-type)应用于Attribute对象(实际上是在其中声明了属性),我稍后会在运行时将它们统一化。猜测与作曲时间有关的事物。但是要确定这里是否有任何遗漏。
无可奉告。您深陷胆量,我根本不相信您想成为那些胆量而不是其他胆量。
是否有比$ value ~~ $ type更好的类型检查方法?
还有其他方法。 $value
是通用智能匹配运算符,在某些情况下会进行缓慢的类型检查。一个关键问题是您要匹配子类型和/或角色,还是仅匹配基本类型。
希望这是值得深思的。