强制/类型检查:手动复制Perl6标准

时间:2018-08-31 14:33:07

标签: perl6

我有一个模块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方法获取参数化类型的基本类型的好主意。

到目前为止,最大的问题在于:

  1. 要检查类型是否已参数化,我不能使用单个角色或类进行匹配。到目前为止,我唯一的方法是查找是否存在of方法并测试其输出。不幸的是,如果一个类提供FALLBACK,则将产生非常不清楚的错误消息(关于AUTOGEN的错误消息)。 :no_fallback是可取的,但是确定类型和子集类型具有自己的find_method,它不支持命名参数,最后我会收到另一条错误消息。
  2. 如果将我的特征角色的$!coerce-type方法中的prepare类型相关属性(compose)应用于Attribute对象(实际上是在其中声明了属性),我稍后会在运行时统一。猜测与作曲时间有关的事物。但要确定这里是否没有遗漏。
  3. 是否有比$value ~~ $type更好的类型检查方法?

1 个答案:

答案 0 :(得分:3)

2019更新,我在写完此答案后不久即删除了该答案。这是一个答案。它没有直接解决问题中提出的大多数问题。在哪里,我不得不说的非常模糊。但是我只是有理由对其进行审查,因此决定暂时最好将其恢复(进行了一些编辑以提高我在其中看到的有用性)。也许Vadim只会删除整个问题,但我想也许它是一个有用的例子,表明对于像Vadim和我自己这样的不熟悉P6元编程内胆的人来说,会是什么样子。希望未来几年会出现真正的答案。


(这不是一个答案,甚至没有结束。这只是对您的问题的探索性评论。它不完全符合评论的要求;完全不属于SO。但是Perl的人不会以“错误”的方式做事,而且我们并不总是像更广泛的社区所说的那样那样写问题或答案。这仅仅是做“错”或至少做“错”的典范。)


对我有帮助的一件事(也许还有一些没有在您闲逛的地方闲逛的人,所以不知道是什么驱动了您)将对我有所帮助。为了表达我的第一条评论:

  

我有一个模块AttrX :: Mooish

The Mooish module's Description说:“该模块旨在提供Moo / Moose所缺少的某些功能。目前,它通过附带的方法实现了懒惰。但是将来还会有更多。”

我无法从中得知您的问题,而这是促使您执行此操作的原因。让我问一下您的动机是否符合以下一种或所有某些人为的可能性:

  1. 如果您今年要在P6中编写代码,则今年需要此功能;

  2. 即使您需要花费一年的时间,您仍希望将此功能引入P6;

  3. 您想在今年最多挑战一次挑战来学习P6;

  4. 您想为在2019年建立P6做出贡献,并考虑在今年提供像P6 Moo这样的纯材料,这对于实现这一目标来说是一件大事;

  5. 上述内容的某种组合,可能具有不同的计时参数或其他动机。

阐明您的动机的评论可能有助于直接回答您的问题。至少会很有趣。 :)

  

实现了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的思考范围。

Strmy 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是通用智能匹配运算符,在某些情况下会进行缓慢的类型检查。一个关键问题是您要匹配子类型和/或角色,还是仅匹配基本类型。


希望这是值得深思的。