100 种语言速通:第 26 集:Raku (Perl 6)

Q神日志 2023-06-25 09:49:04

Raku 最初是 Perl 6,旨在作为 Perl 语言的继承者。

主要问题是 Perl 6 于 2000 年正式发布,直到 2015 年才正式出现,在这段时间内 Perl 失去了大部分受欢迎程度,大多数人转向了 Ruby、PHP 或 Python。

Raku 并不试图实现与 Perl 5 的兼容性,但它遵循非常相似的风格。在 2000 年 Perl 非常流行的时候,这似乎是一个好主意,但现在已经不那么流行了。

但除了刚刚清理的 Perl 5 之外,Raku 还有一些非常酷的新概念,绝对值得一看。

你好世界!

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Hello, World!</span><span style="color:var(--syntax-text-color)">";</span>
</code></span></span>

 

这里需要注意两件事。

The good thing - say is a really nice name. Of all the words languages use for this concept, I think say is much better than print or puts or console.log or println or prn or writeln and so on. Raku uses a lot of new names for various functions, some quite good, some not so much.

The bad thing - damn mandatory semicolons. Somehow Raku didn't drop this nonsense, even though they've been dropped by nearly every modern language by now, as well as by all good JavaScript coding styles (if you're coding JavaScript with semicolons, you're doing it wrong).

每一个无用的标记都会增加精神负担,每一个无意义的“错过分号”错误都会花费程序员的时间和注意力——极其有限的资源。没有理由在任何新语言中强制使用分号。

Perl 和 Raku 中的分号是语句分隔符而不是终止符,因此与 C/Java/等不同。您可以跳过它们来查看块的最后一条语句。

菲兹巴兹

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-declaration-color)">sub </span><span style="color:var(--syntax-name-color)">fizzbuzz</span><span style="color:var(--syntax-text-color)">($n) {</span>
  <span style="color:var(--syntax-text-color)">given</span> <span style="color:var(--syntax-text-color)">$n</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">when</span> <span style="color:var(--syntax-text-color)">$_</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">3</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span> <span style="color:var(--syntax-error-color)">&&</span> <span style="color:var(--syntax-text-color)">$_</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">5</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">FizzBuzz</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">when</span> <span style="color:var(--syntax-text-color)">$_</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">3</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Fizz</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">when</span> <span style="color:var(--syntax-text-color)">$_</span> <span style="color:var(--syntax-error-color)">%</span> <span style="color:var(--syntax-literal-color)">5</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">0</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Buzz</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">default</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">$_</span> <span style="color:var(--syntax-text-color)">}</span>
  <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">100</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">fizzbuzz</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$_</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

这是执行 FizzBu​​zz 的一种方法。循环非常好,1..100for range from 1to比约定100更有意义。range(1, 101)

Raku 就像 Perl$_在很多上下文中使用默认变量一样,例如for循环和given块。只是为了澄清 - 这两个$_不会互相覆盖,每个都$_特定于其块。

斐波那契

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">multi</span> <span style="color:var(--syntax-declaration-color)">sub </span><span style="color:var(--syntax-name-color)">fib</span><span style="color:var(--syntax-text-color)">(1) {</span> <span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">multi</span> <span style="color:var(--syntax-declaration-color)">sub </span><span style="color:var(--syntax-name-color)">fib</span><span style="color:var(--syntax-text-color)">(2) {</span> <span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">multi</span> <span style="color:var(--syntax-declaration-color)">sub </span><span style="color:var(--syntax-name-color)">fib</span><span style="color:var(--syntax-text-color)">($n) {</span> <span style="color:var(--syntax-text-color)">fib</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$n</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">fib</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$n</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">30</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">fib</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$_</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

Raku 允许定义多个具有相同名称的函数,根据参数数量、类型或值进行匹配。这看起来很像 Haskell。

平等

是时候讨论 Perl 设计中最糟糕的部分了,100% 都被复制到了 Raku 中。没有“数字”或“字符串”。这只是标量,它们会自动转换。

但事情没那么简单。22.0是相同的东西(作为数字),但"2""2.0"完全不同(作为字符串)。因此 Perl 和 Raku 拥有完全并行的运算符集。对于像连接这样的东西(2 ~ 2is 22+总是数字)这很好,但绝对最糟糕的是有两个相等:==数字和eq字符串。

这有什么问题吗?嗯,在具有普通==运算符的普通语言中,它不仅可以用于数字和字符串,还可以用于数组、散列、集合或我们扔给它的任何其他东西。

在 Raku 中,我们有这样的令人厌恶的事情:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-comment-color)"># Numerical</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">2.0</span><span style="color:var(--syntax-text-color)">";</span>

<span style="color:var(--syntax-comment-color)"># String equality</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">hello</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">hello</span><span style="color:var(--syntax-text-color)">";</span>

<span style="color:var(--syntax-comment-color)"># Looks like it works...</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-comment-color)"># Raku sorts the key order (unlike Ruby) so they match</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">b</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">b</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-comment-color)"># WTF? How is any of these True?</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">["</span><span style="color:var(--syntax-string-color)">one</span><span style="color:var(--syntax-text-color)">",</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">two</span><span style="color:var(--syntax-text-color)">"]</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">one two</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">["</span><span style="color:var(--syntax-string-color)">1 2</span><span style="color:var(--syntax-text-color)">"];</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">1 2</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-literal-color)">\t</span><span style="color:var(--syntax-string-color)">1</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">b</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-literal-color)">\t</span><span style="color:var(--syntax-string-color)">1</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)">b</span><span style="color:var(--syntax-literal-color)">\t</span><span style="color:var(--syntax-string-color)">2</span><span style="color:var(--syntax-text-color)">";</span>
</code></span></span>

 

这是True为他们每一个人准备的。

还要注意完全疯狂的默认字符串化规则 ( Str()) - 而不是像Str([1, 2])那样明智的东西[1, 2],它是"1 2". 对于哈希值来说,那些制表符和换行符到底是怎么回事?

JSON

还有另一种打破不平等的流行语言——JavaScript。传统的解决方法是JSON.stringify(a) === JSON.stringify(b).

让我们看看情况如何。首先,Rakudo 在标准库中没有 JSON,也没有包管理器。

我需要brew uninstall rakudo moarvm nqp得到brew install rakudo-star它的zef包管理器。这确实很奇怪,但是很多语言都有打包怪癖,所以让我们继续吧。我实际上不需要安装任何软件包,因为rakudo-star软件包(但不是rakudo软件包)已经包含在内JSON::Tiny

但是等一下,如果 Raku 不能区分数字和字符串,它怎么能处理 JSON!

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">JSON::</span><span style="color:var(--syntax-text-color)">Tiny</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">to</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">([</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]);</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">to</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">(["</span><span style="color:var(--syntax-string-color)">1</span><span style="color:var(--syntax-text-color)">",</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">2</span><span style="color:var(--syntax-text-color)">"]);</span>
</code></span></span>

 

事实证明这工作得很好:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./json.raku
[ 1, 2 ]
[ "1", "2" ]
</code></span></span>

 

Raku 的行为就好像数字和字符串之间没有区别,但它内部存在于幕后。数字2和字符串"2"99% 相同,除非它们不同。

我仍然记得 Perl 时代的这个错误,打印变量会改变它的类型:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/perl -l</span>

<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">JSON</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">my</span> <span style="color:var(--syntax-text-color)">$x</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">print</span> <span style="color:var(--syntax-text-color)">encode_json</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$x</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">print</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">$x</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-declaration-color)">print</span> <span style="color:var(--syntax-text-color)">encode_json</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$x</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>

 

这导致了这个WTF:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./json_bug.pl
2
2
"2"
</code></span></span>

 

所以你会打印一些东西来调试,突然你的程序会完全不同地工作。那是一个有趣的夜晚,15 年后我仍然记得它,而且那个问题比这个埋得更深。

无论如何,我无法在 Raku 中重现它:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">JSON::</span><span style="color:var(--syntax-text-color)">Tiny</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">my</span> <span style="color:var(--syntax-text-color)">$x</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">to</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$x</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">$x</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">to</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$x</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>

 

它绝对有效的地方:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./json_bug.raku
2
2
2
</code></span></span>

 

但我们可能仍然会遇到数字和字符串 99% 相同的问题,除非它们不同。也许更有经验的 Raku 程序员可以告诉我如何在 Raku 中触发这个问题。

哦,请注意支持短横线大小写标识符。

JSON 相等

让我们尝试一下 JSON 的相等性:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-declaration-color)">use</span> <span style="color:var(--syntax-text-color)">JSON::</span><span style="color:var(--syntax-text-color)">Tiny</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">sub </span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">-equal($a, $b) {</span>
  <span style="color:var(--syntax-text-color)">to</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$a</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">to</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$b</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-comment-color)"># True as expected</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">([</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">],</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]);</span>

<span style="color:var(--syntax-comment-color)"># False as expected</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">([</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">],</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">[1, 2]</span><span style="color:var(--syntax-text-color)">");</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">("</span><span style="color:var(--syntax-string-color)">2</span><span style="color:var(--syntax-text-color)">",</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">2.0</span><span style="color:var(--syntax-text-color)">");</span>

<span style="color:var(--syntax-comment-color)"># Also True...</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">5.0</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">);</span>

<span style="color:var(--syntax-comment-color)"># Also False...</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">1</span><span style="color:var(--syntax-text-color)">");</span>

<span style="color:var(--syntax-comment-color)"># Totally random if True or False</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-text-color)">equal</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">b</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">a</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">b</span><span style="color:var(--syntax-error-color)">=></span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">});</span>
</code></span></span>

 

前三项测试都很好。那么55.0是相同的,就像0-0- 因为这些实际上是大有理数而不是浮点数,所以我们暂时不要进入 Raku 数字系统。

1并且"1"与 JSON 不相等是我们已经知道的事情。

但是 和{b=>2, a=>1}{a=>1, b=>2}Str()总是对它们的键进行排序,因此它们总是eq,但是对于 JSON 转换,它们的顺序无法保证,因此该程序将打印TrueorFalse随机。

总的来说,彻底的灾难。这个问题是可以解决的,但从我的 Perl 和 JavaScript 经验来看,没有通用性==是一个经常出现的巨大痛苦。

EQV

哦等等,我们还没有完成。有eqv!让我们看看它是如何做的:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>#!/usr/bin/env raku

# True as expected
say [1, 2] eqv [1, 2];
say {b=>2, a=>1} eqv {a=>1, b=>2};

# This is still True
say 0 eqv -0;

# False as expected
say [1, 2] eqv "[1, 2]";
say "2" eqv "2.0";

# Now this is False too?
say 5 eqv 5.0;
say 1 eqv "1";
</code></span></span>

 

这是迄今为止我们得到的最接近的结果。1与众不同"1"是我们已经知道的。但现在55.0被视为eqv不同的(作为整数和有理数),即使到目前为止它们在其他地方都是如此。==它仍然是我们迄今为止得到的最好的,但在本世纪设计一种没有通用性的语言真是太尴尬了。

统一码

至少 Perl 从来没有遇到过 Unicode 问题,Raku 也没有:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">uc</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Żółw</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">chars</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Żółw</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">chars</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">🍰</span><span style="color:var(--syntax-text-color)">";</span>
</code></span></span>

 

哪个输出完全正确:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./unicode.raku
ŻÓŁW
4
1
</code></span></span>

 

状态和哈希

让我们再做一次斐波那契数列,除了记忆:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-declaration-color)">sub </span><span style="color:var(--syntax-name-color)">fib</span><span style="color:var(--syntax-text-color)">($n) {</span>
  <span style="color:var(--syntax-text-color)">state</span> <span style="color:var(--syntax-text-color)">%cache</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-text-color)">%cache</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-text-color)">$n</span><span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-string-color)">//</span><span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">fib</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$n</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">fib</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$n</span> <span style="color:var(--syntax-error-color)">-</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">fib</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$_</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">..</span><span style="color:var(--syntax-literal-color)">1000</span>
</code></span></span>

 

Raku 有很多范围。my是通常的局部变量。state其作用域仅限于其函数,但它们仅初始化一次。

变量类型可以通过印记推断 -$是标量(字符串、整数等)。@是数组。%是哈希(或字典)。因为 Raku 知道它们的类型,所以它可以初始化它们以纠正空值 - 但在这种情况下,我们自己初始化它。

A //= B如果 A 缺失,则将其设置为 B(||=检查 A 的真实性,但这不是我们想要的,因为 0、空字符串等在 Raku 中都是 false)。它还返回返回值。

因此,对于没有专门记忆化内置支持的语言来说,这是一种极其简洁的记忆化方法。

哦,您可以使用if,for等后缀。这肯定会提高“保护子句”(return if ...return unlessbreak if ...)的可读性,这里不一定需要for循环。

路口

您是否曾经想编写if x == 1 | 2 | 3,但您的语言不支持它,因此您需要这样做if x == 1 || x == 2 || x == 3

我有一些好消息!

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">What's your name?</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-declaration-color)">my</span> <span style="color:var(--syntax-text-color)">$name</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$name</span> <span style="color:var(--syntax-error-color)">eq</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">admin</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">root</span><span style="color:var(--syntax-text-color)">")</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Don't try to hack me</span><span style="color:var(--syntax-text-color)">"</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Hello, </span><span style="color:var(--syntax-string-color)">$name</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

让我们尝试一下:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./junctions.raku
What's your name?
Alice
Hello, Alice
$ ./junctions.raku
What's your name?
admin
Don't try to hack me
</code></span></span>

 

get读取一行,并|创建一个“连接点”。它是一种模式(and、or、one、none)中的值的集合,它尽可能长时间地对每个元素执行所有操作。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Some of them match!</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">4</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">All of them match!</span><span style="color:var(--syntax-text-color)">"</span> <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">2</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">4</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">5</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>

 

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./junctions2.raku
Some of them match!
All of them match!
</code></span></span>

 

仅当在布尔上下文中求值时,连接才会折叠为单个值。代码的意思是:

  • 1 * 2( , 2 * 2, )之一等于 ( , )3 * 2之一45
  • 所有 ( 1 * 2, ) 等于 ( , , )2 * 2之一452

连接对于 Raku 来说非常独特,我不知道它们是否真的使编码变得更容易,或者它们只是不必要的复杂性。

常用表达

Perl 推出了自己的扩展正则表达式,现在每种语言都使用 Perl 风格的正则表达式,因此它取得了巨大的成功。Perl 之前的版本基本上已经被遗忘了。Perl 的正则表达式至少在很大程度上与 Perl 之前的类型兼容,因此它们仅限于在一些扭曲的组合中使用少量符号来实现额外的功能。

Raku 显然引入了自己的正则表达式系统,该系统试图更具表现力,并且故意不向后兼容。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">What's your name?</span><span style="color:var(--syntax-text-color)">";</span>
<span style="color:var(--syntax-declaration-color)">my</span> <span style="color:var(--syntax-text-color)">$name</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">$name</span> <span style="color:var(--syntax-error-color)">~~</span> <span style="color:var(--syntax-string-color)">/^<[a..z]>+$/</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">/^<[A..Z]>+$/</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Hello, </span><span style="color:var(--syntax-string-color)">$name</span><span style="color:var(--syntax-text-color)">"</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">"</span><span style="color:var(--syntax-string-color)">Please use consistent case</span><span style="color:var(--syntax-text-color)">"</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

这里发生了什么...

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./regexp.raku
What's your name?
alice
Hello, alice
$ ./regexp.raku
What's your name?
BOB
Hello, BOB
$ ./regexp.raku
What's your name?
Charlie
Please use consistent case
</code></span></span>

 

首先,模式匹配~~(Perl 和 Ruby 使用=~)。的任何结点|。两者都不是特定于正则表达式的。

有趣的事情从 开始/^<[a..z]>+$/。Raku 正则表达式有很多新功能,因此他们必须更改一些现有语法,为所有新功能腾出空间。字符范围[a-z]变为<[a..z]>. 被[]重新调整为非捕获组((?:)在 Perl 正则表达式中),这可以说是更重要的功能。

Raku 正则表达式的主题足够大,我需要用一整集来讨论它。它基本上是一种语言中的一种语言。

统一码运算符

Raku 的语法中包含 Unicode 运算符,这确实不足为奇。继 Julia 之后,这是我们正在研究的第二种语言,我预计这将成为未来新编程语言的主流功能。

移植 Julia 的示例:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env raku</span>

<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> ⊆ <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">,</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-literal-color)">3</span> ∈ <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">,</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-text-color)">say</span> <span style="color:var(--syntax-text-color)">(</span>π<span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">sin</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">sqrt</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>

 

它输出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./unicode_operators.raku
True
True
1.4999999999999998
</code></span></span>

 

就像在 Julia 中一样,设置操作与和 的工作方式相同。π是通常的常数。与 Julia 不同的是,.sin是一个方法而不是一个独立的函数,并且.sqrt是一个方法并且没有.

Raku 和 Julia 都没有过度使用 Unicode 运算符,但它们绝对可以使数学代码更具可读性。

厨房水槽语言设计

Raku 是一种类似于 Perl 或 Scala 的厨房水槽语言。他们倾向于尝试所有的想法,勇敢地打破通行假设,其中一些结果证明是惊人的。但所有不太好的想法都具有很高的心理成本,因此厨房水槽语言也往往在最不喜欢的排行榜上名列前茅。

有时它会产生奇迹。Perl 可能已经远未达到它的流行顶峰,但它将作为几乎所有现代编程语言的祖先而永远存在。Ruby、JavaScript、PHP(以及较小程度上的 Python)基本上都是 Perl 的子代,而这些语言反过来又影响了其他一切。它彻底改变了编程语言的设计。只需将 Perl 之前的最后一个主要语言 Java 与 Perl 之后的任何设计进行比较即可,它完全是可用性灾难。

在较小的规模上,CoffeeScript 试图让 JavaScript 变得可以忍受,虽然它现在基本上已经死了,但如果没有 CoffeeScript 铺平道路,ES6+ 就不会存在。

但通常情况下,它根本不起作用。像 Raku 或 Scala 这样的厨房水槽语言并没有走得太远,到目前为止也没有对其他语言产生太大影响。

你应该使用 Raku 吗?

如果您对编程语言设计感兴趣,或者考虑设计自己的编程语言,Raku 绝对值得一试,即使您不打算在其中编写任何实际代码。它尝试了很多东西,我在这里仅仅触及了皮毛。

如果您是一名 Perl 程序员,但出于某种原因不想像大多数人一样切换到 Ruby 或 Python,那么 Raku 可能值得一试。对我来说,它保留了 Perl 的太多糟糕的设计理念,但如果你已经接受了成本,也许这不是什么大问题。

另一方面,如果你认为 Ruby 已经是 Perl 6,或者不能忍受 Perl 风格的语言,那么 Raku 就非常没有吸引力了。

我还没有真正探索过 Raku 在实用方面的表现如何,比如它的生态系统、性能等等。乍一看,它看起来不太好。

我绝对会推荐 Raku 作为语言来度过一个有趣的周末,即使很少有人愿意用它来做更严肃的事情。

 


关注我的博客,您将在其中获得提示、技巧和挑战,以保持您的技能敏锐。记得关注我哦!

...全文
161 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

6

社区成员

发帖
与我相关
我的任务
社区描述
分享
java-rocketmqpygame前端 个人社区 广东省·广州市
社区管理员
  • Q shen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧