第十一天 - 使用 Raku 测试你的时刻表

Testing Your Times Tables With Raku

这几乎是在北极附近的精灵小学冬季学期结束之时。对于精灵而言,敏锐的人物头脑非常重要,而小精灵的数学老师 Hopper 女士希望确保他们在任期的倒数第二天保持他们的算术技能。(学期的最后一天保留用于观看电影和玩耍 - 很嗨皮)。

小精灵刚刚学会了他们的时间表(乘法表),最多12个,但他们并不像他们所想的那样擅长,其中一些人在圣诞节前将在玩具工作坊帮忙,那时候他们可能需要快速告诉大精灵有多少特定类型的玩具。

幸运的是,Elf Hopper 是一个非常聪明的精灵,拥有出色的数学和编码能力 - 自己。所以她起了一个快速的控制台应用程序来运行小精灵的学校颁发的 Perlix 6.0 boxen。

该程序允许小精灵通过运行它们在2至12次表中测试自己,或者如果它们提供单个数字参数,他们可以尝试任何他们喜欢的乘法表。

#!/usr/bin/env raku

use v6;

my $fixednum;
my %score;
my @exits = <exit quit>;

$fixednum = @*ARGS[0] || 0;
put "Type the answer, or quit or exit to end the test.";


loop {
    my $coefficient = (2..12).pick;
    my $number = $fixednum || (2..12).pick;

    my $answer = prompt ( "$coefficient × $number = " );
    my $rightanswer = $coefficient × $number;

    last if $answer.lc ~~ any @exits;

    if $answer == $rightanswer {
        put "Correct!";
        %score<correct>++;
    } else {
        put "Sorry, that wasn't right! The answer is $rightanswer";
    }
    %score<total>++;
}

if %score<total>:exists {
    my $pc = 100 * %score<correct> / %score<total>;
    put "You scored %score<correct> out of %score<total>, i.e. ", sprintf "%2.2f%%.", $pc;
}

Elf Hopper 向其它小精灵解释代码如下。

“可爱的小精灵们!这是关于程序如何工作的一些背景知识。

我在顶部附近添加了 use v6;,以便代码也可以在 Perl 5下 运行,它将自动使用 Raku 仿真器。

您将看到程序在特殊的 @*ARGS 数组的命令行上运行时选择一个可选参数。这是 Perl 5 的 @ARGV 数组的 Raku 等价物。

在 Raku 中,数组,数组元素和数组切片总是使用 @ sigil,与 Perl 5 不同,其中各个数组元素使用 $ sigil。同样,哈希和哈希元素现在总是带有 % sigil,无论是整个哈希,它的切片还是单个元素都在使用。

那里还有另一个符号,星号 ‘twigil’,*。这表明 @*ARGS 是一个动态特殊变量。

promptloop 关键字是 Raku 中的新功能,两者都是令人钦佩的名字!

  • prompt 只返回用户输入的值,在本例中为变量。
  • loop 是 Raku 的新块控制关键字之一。像这样的简单循环块只是创建了一个无限循环,可以由程序员以显式的方式结束,例如在满足条件时使用 last 关键字;或者例如由用户手动终止程序。
  • 或者,循环可以采用三个参数,并且表现得像传统的C风格 for 循环。 (在 Raku 中,小精灵,for 只用于迭代列表或其他容器。)

在循环内部,小精灵,你可以看到范围对象。一切都是 Raku 中的一个对象,所以我可以在范围上调用 pick 方法来返回一个随机数。(好吧,无论如何,这是一个非加密安全的伪随机数!)

any 关键字将 @exits 数组转换为 Raku 中许多新的有用数据结构之一:一个 Junction。这使得使用 smartmatch 运算符 ~~ 直截了当地找到一个数组元素。last 关键字退出循环,如 Perl 5 中所示。

Junction 是一种新类型的容器或列表,允许进行许多最有用的比较,例如 anyallonenone,我们在 Perl 5 中使用 grepList::Util 等模块进行比较,但它使它们成为可能键入更容易,并允许它们同时执行!这样做的一个副作用是 junction 是无序的:但它们主要是为了产生单个真值或假值,所以通常都可以。如果你想快速想要根据一些特定值的简短列表检查一个值,那么 junction 就很棒。但是如果需要的话,它们还能够让你匹配更大的值集。

在最后一个代码段落的顶部,您将看到 :exists 应用于 %score<total> 哈希键。:exists 是一个 Raku 副词!副词通常会修改方法的工作方式。:exists 是下标副词。它是一个副词,因为它改变了读取哈希键时发生的事情:不是返回值,而是查明值是否存在。这通常是使用 Perl 5 类中关注的那些熟悉的已定义方法的更好的替代方法。

当然,exists 测试就是为了确保在用户第一次退出程序时不会出现错误。

为什么我使用锯齿形符号来引用哈希键?好吧,花括号 {} 是散列键的标准下标运算符,如 Perl 5. 但是,大多数情况下你可能想要使用尖括号/锯齿形符号,因为它们提供单字键的自动引用。用于在 Perl 5 中执行此操作的简单{} 括号,但在 Raku 中不再执行此操作。需要引起括号内的字符串。

在 Raku 中,放置了用于向终端输出文本的标准命令。这将输出以下列表项,然后是换行符。sayprint 仍然可用; sayput 这两个都打印到标准输出并添加换行符; print 不会追加换行符。

如果你使用这个程序以及知道它是如何工作的,小精灵,你将有选择和知识,是否,何时以及如何在你自己的头脑中执行乘法,以及什么时候最好让 Raku -有动力的电脑做它。您的圣诞节作业是让您自己熟悉https://docs.raku.org 上的 Raku 文档。“

小精灵开始使用乘法测试程序,试图超越对方以获得最高的完美分数。他们发现它如此令人上瘾,以至于比赛甚至会加时到在学校的最后一天,当时他们应该正在观看’精灵'!

comments powered by Disqus