打高尔夫球的技巧在Perl 6


16

您在Perl 6中打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫问题的想法,这些想法至少在某些方面是Perl 6特有的(例如,“删除评论”不是答案)。请为每个答案发布一个提示。

请注意,Perl 6不是Perl 5,因此此问题不是重复的。有关Perl 5高尔夫的大多数技巧只是不适用于Perl 6。

Answers:


9

避免使用sub文字。在许多情况下,您可以简单地将其{}用于代码块。例如,不要编写以下代码。

sub ($a){$a*2}

而是使用块语法。如果只需要一个变量,这也使您可以使用$_@_%_占位符变量。如果您需要更多,可以使用$^a$^b变量等。

{$_*2}

同样,在某些罕见的情况下,可以使用任何代码(尤其是当您具有简单表达式时)。该*替换占位符参数。

* *2

8

Perl 6具有一个非常奇怪的功能,它允许类别NdNl和  No中的所有 Unicode字符用作有理数文字。其中一些比用ASCII写出它们的数值短:

  • ¼(2个字节)短于.251/4(3个字节)。
  • ¾(2个字节)短于.753/4(3个字节)。
  • (3个字节)比1/16(4个字节)短。
  • 𐦼(4个字节)比11/12(5个字节)短。
  • 𒐲(4个字节)比216e3(5个字节)短。
  • 𒐳(4个字节)比432e3(5个字节)短。

作为后续操作,您也可以使用Unicode指数,即使有多个数字和/或减号也是如此:say (3² + 4², 2²⁰, 5⁻²)==> (25 1048576 0.04)。您可以在此处滥用的Unicode的完整列表在这里:docs.perl6.org/language/unicode_texas
拉米利斯

8

了解读取输入的功能。Perl 6具有许多有趣的功能,可以轻松地从ARGV或STDIN读取输入(如果ARGV上未指定任何内容),如果使用正确,则可以缩短代码。如果将它们作为文件句柄方法调用,则可以强制它们在特定的文件句柄上工作(例如STDIN,如果您从中读取,则很有用,但必须读取ARGV上的参数)。

get

此函数仅获得一行,并自动将其斩断,因此您不必这样做。如果您只需要阅读一行,这将很有用。

lines

此函数从文件或STDIN获取所有行。这是一个惰性列表,因此,如果将其与一起使用for,它将仅读取您需要的内容。例如。

say "<$_>"for lines

slurp

这将读取整个文件或STDIN,并将结果作为单个字符串返回。


该错误已修复-不知道何时出现,但say "<$_>" for lines现在可以正常工作

5

警告:文字墙正在接近。随着时间的推移,我收集了很多小技巧。

将您的解决方案写为匿名块

已经提到过这一点,但我想重申一下。在TIO中,您可以将其写入my $f =页眉,将该块写入适当的代码,然后以开头;。到目前为止,这似乎是完成工作的最短方法(因为您无需关心读取任何输入,因此它会在参数中提供给您)。

另一种不错的方法是使用-n-p开关,但我找不到使它在TIO中工作的方法。

使用冒号语法传递参数

也就是说,代替 thing.method(foo,bar),你可以做thing.method:foo,bar,并保存1个字符。不幸的是,出于明显的原因,您不能在结果上调用另一个方法,因此仅对块中的最后一个方法使用才有意义。

采用 $_尽可能多地

因此,有时使用单个列表参数比使用几个单独的参数更好。访问时$_,您可以仅以点开头来调用方法:例如.sort等于$_.sort

但是,请记住,每个块都有自己的块 $_,因此外层块的参数不会传播到内层块。如果需要从内部块访问主功能的参数,则...

使用 ^如果不能使用,变量$_

^在符号和变量名称之间插入一个,如下所示:$^a。这些仅在一个块内起作用。编译器首先计算块中有多少个,按字典顺序对它们进行排序,然后将第一个参数分配给第一个参数,第二个参数分配给第二个参数,依此类推。在^仅在可变的第一次出现所使用的需求。因此,{$^a - $^b}取2个标量并减去它们。唯一重要的是字母顺序,{-$^b + $^a}同一件事也是如此。

如果您想使用尖的块语法(如->$a,$b {$a.map:{$_+$b}}),最好在块的开头使用^将要在主块中不使用的每个参数(如)编写伪语句{$^b;$^a.map:{$_+$b}}(注意这是一种更好的高尔夫方式{$^a.map(*+$^b)}。我只是想炫耀这个概念。)

仔细阅读操作员文档

操作员功能强大,通常是完成工作的最短方法。特别是元符(需要运营商作为一个参数运营商)[][\]X<</ >>Z是你的注意力的价值。不要忘记一个meta-op可以接受另一个meta-op作为参数(就像XZ%%我设法在这里使用的)。您也可以使用>>方法调用,它比映射便宜很多(@list>>.method代替@list.map(*.method),但要注意,它们并不相同!)。最后,在使用二进制文件之前,请<< >>记住,Z这样做通常会用更少的字符来完成相同的操作。

如果您将许多元操作相互叠加,则可以使用方括号指定优先级[]。当您堆积过多的运算符以致使编译器混乱时,这将节省您的时间。(这种情况很少发生。)

最后,如果你需要强迫事情BOOL,INT或STR,不使用方法.Bool.Int.Str,而是运营商?+~。甚至更好,只需将它们放入算术表达式中以将其强制为Int等等。获取列表长度的最短方法是+@list。如果您想计算2到列表长度的幂,只需说2**@list,它将做正确的事情。

使用自由状态变量$@以及%

在每个块中,每一次出现$(或@%)指的是一个全新的标量(或阵列,或散列)状态变量(一个变量,其值保持在调用给块)。如果您需要一个状态变量,而该状态变量只需要在源代码中被引用一次,那么这三个是您的好朋友。(通常是$。)例如,在“ 逆数学循环”挑战中,可以使用它从数组中循环选择运算符,该数组由索引$++%6

使用mapgrep等的子形式。

那意味着:做而map {my block},list不是做list.map({my block})。即使您设法使用list.map:{my block},这两种方法也会以相同的字节数出现。通常,在调用方法时需要在列表中加上括号,而在调用子方法时则不需要。因此,子方法总是比方法1更好或至少相同。

这里唯一的例外是当要进行mapped,grepped等操作的对象处于in中时$_。然后.map:{}明显跳动map {},$_

使用结点(&|)代替&&||

显然,它们短了1个字节。另一方面,必须通过将它们强制为布尔上下文来使其崩溃。始终可以使用来完成此操作?。在这里,您应该意识到!op强制布尔上下文,使用op和否定结果的元操作。

如果您有列表,并且想要将其转换为联结,请不要使用[&][|]。而是使用.any.all。还有.none那些不能被结ops轻易地模仿。


1
我认为&&并且||对于短路仍然有用吗?
仅使用ASCII

仅限@ASCII:是的,当然可以。
Ramillies

4

减少用于变量的空间

有几个部分。

删除空格

使用my声明的变量通常可以在my和变量名之间没有空格的情况下声明。my @a等同于my@a

使用无符号变量

您可以使用反斜杠声明变量,以在变量名称之前删除符号,如下所示:

my \a=1;

(很遗憾,您不能删除空格:()

这很有用,因为以后您可以将它们仅用作裸变量名称。

 a=5;
 a.say

基本上,如果您在代码的其他位置多次使用变量,则可以节省字节。缺点是该变量需要初始化。

使用$!$/

这些预先声明的变量通常分别用于异常和regex匹配,但不需要使用进行定义my

$!=1;
$/=5;

尤其有用的是$/用作数组,并使用快捷方式$后跟数字以访问$/数组的该元素;

$/=100..200;
say $5;  #105
say $99; #199

2

使用...代替first

通常,如果要查找与某些条件匹配的第一个数字,&f可以将其表示为:

first &f,1..*

但是,您可以使用...运算符:

+(1...&f)

如果必须从头开始0,则可以-1事后代替+

如果要获取@a具有condition 的列表中第一个元素的索引&f,通常可以执行以下操作:

first &f,@a,:k

代替:

(@a...&f)-1

(反之亦然,如果您想索引0)。以相同的方式,您可以使所有元素达到第一个通过条件的元素。

不利的一面是列表必须在某个点通过条件,否则...操作员将尝试从列表末尾推断,并很可能引发错误。您也不能在左侧使用任何代码,因为它将被解释为序列的一部分。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.