清洁高尔夫技巧


17

您在Clean中打高尔夫球有哪些一般秘诀?请仅发布可用于一般性编码高尔夫球问题的想法,至少应针对清洁运动。

如果您从未听说过Clean,可以在这里找到更多信息
或者,您可以加入聊天室

Answers:


10

import StdEnv尽可能避免

要访问内置功能,甚至需要看似基本的功能(如(==)或)map,也需要使用import语句,通常是import StdEnv因为它导入了最常见的模块(如StdIntStdBool等等)(有关更多信息,请参见此处StdEnv)。

但是,可以避免这种导入带来一些挑战,而仅使用诸如列表理解和模式匹配之类的核心语言功能即可。

例如,代替

import StdEnv 
map f list

一个可以写

[f x\\x<-list]

替代品清单:

一些需要的函数或函数调用,不需要import StdEnv导入的替代方法或对所保存字节的粗略估计。

  • hd-> (\[h:_]=h),〜6个字节
  • tl-> (\[_:t]=t),〜6个字节
  • map f list-> [f x\\x<-list],〜10个字节
  • filter p list-> [x\\x<-list|p x],〜11个字节
  • (&&)-> %a b|a=b=a;%,〜6个字节
  • (||)-> %a b|a=a=b;%,〜6个字节
  • not-> %a|a=False=True;%,〜1个字节
  • and-> %[a:r]|a= %r=a;%_=True,〜0字节
  • or-> %[a:r]|a=a= %r;%_=False,〜0字节

最后几个不太可能实际保存字节,因为直接替换产生的字节数比导入的要多,但是无论如何还是需要在列表上进行递归。

这个技巧已经在这里成功使用。


是不是import StdEnv+ a and b(21个字节)小于%[a:r]|a= %r=a;%_=True(22个字节),但?或者是import StdEnv+ a=True and b=True(31个字节),在这种情况下确实肯定要短一些?(顺便说一句,我从来没有在Clean中编程)
Kevin Cruijssen

@KevinCruijssen我们只是在聊天中讨论。的确,除非程序需要在列表上递归,否则它们不太可能保存字节。
Laikoni '18

4
喔好吧。声明备用选项保存多少字节(即map f list -> [f x\\x<-list] (11 bytes saved)(或类似的东西))也许也很有用。
凯文·克鲁伊森

@KevinCruijssen完成。
Laikoni

5

懂得学习语言

毕竟,任何人都不能用他们无法使用的语言打高尔夫球!

线上

清洁不是一种众所周知的或有据可查的语言,而且这个名称当然不能轻易地找到急需的资源来解决这些问题……或者是吗?

Clean最初称为Concurrent Clean,几乎在与Clean相关的所有文档的序言中仍使用Clean-因此,如果您要查找Clean,请改用Concurrent Clean。

Clean与Haskell(其中有很多)最显着的相似之一是Cloogle的存在,它是一个功能搜索引擎,涵盖了Clean随附的库。

在本地

Clean附带的库的形式是经过适当注释的,有点自文档说明的Clean源文件,可以使用IDE对其进行浏览。
(还提供了完整的示例程序,位于下)$INSTALL/Examples

说到它,Windows版本的Clean带有一个IDE-尽管它受到现代标准的相当大的限制,但比使用文本编辑器和命令行要好得多。
在学习中,两个最有用的功能是:

  • 您可以双击错误以查看错误所在的行
  • 您可以突出显示模块名称,然后按[Ctrl]+[D]打开定义文件(或[Ctrl]+[I]用于实现文件),然后使用以下命令在定义和实现文件之间切换[Ctrl]+[/]

4

忘记字符编码

Clean的编译器并不关心您认为将源文件另存为哪种编码,仅关心文件中的字节值。这会带来一些整洁的后果。

在源代码主体中,除的字节外,仅允许其代码点与可打印的ASCII字符相对应的字节\t\r\n

文字:

String[Char]文字中("stuff"['stuff']分别),允许使用除0以外的任何字节,但必须注意"'必须转义(对于String[Char]),并且换行符和回车符必须分别用\n和替换\r

Char文字上,允许使用除0以外的任何字节,这意味着:

'\n'

'
'

相同,但是第二个短一个字节。

转义:

除标准字母转义符\t\r\n(等)外,Clean中的所有非数字转义序列都用于斜杠或用于在转义符内部定界文字的引号。

对于数字转义序列,该数字被视为八进制值,该数字在三位数后终止。这意味着,如果你想有一个空后面跟着一个字符1String,你需要使用"\0001"(或"\0\61")和 "\01"。但是,如果按照逃生与任何东西,但数字,则可以省略前导零。

后果:

Clean如何处理其源文件的这种怪异方法允许String['Char']有效地使其成为以256为基数的个数的序列-该序列对于代码高尔夫球有多种用途,例如存储索引(当然最多可存储255个)。


3

带符号的名称功能

定义函数时,使用的某些组合通常!@$%^&*~-+=<:|>.?/\比使用字母数字字符要短,因为它允许您省略标识符之间的空格。

例如:?a=a^2短于f a=a^2,调用它也短于。

但是

如果功能标识符与其他符号相邻使用,它们可以组合在一起形成一个不同但有效的标识符,则它们都将被解析为一个标识符,您会看到错误。

例如:?a+?b解析为? a +? b

另外:

可以在Clean中覆盖导入的标识符,因此,唯一尚未使用的单字符符号标识符StdEnv@$?^-+如果需要更多的符号标识符,则覆盖(等)很有用,但请注意不要覆盖正在使用的符号。


3

知道你的K个节点

功能语言中最强大的一些构造(用于高尔夫)是let ... in ...
干净当然有这个,还有更好的东西- #

什么是节点?

Clean的#和无处不在的|(模式保护)都称为“节点表达式”。
值得注意的是,它们允许你编程imperatively- ISH在清洁(这是真的好了!)。

#(让-前):

它们都计算以字符串形式给出的整数的值乘以其字符的总和

f s=let i=toInt s;n=sum[toInt c\\c<-:s]in n*i

f s#i=toInt s
#s=sum[toInt c\\c<-:s]
=s*i

注意with的版本#更短,以及如何重新定义s。如果我们在接收变量时不需要变量所具有的值,则这很有用,因此我们可以重复使用该名称。(let这样做可能会遇到问题)

但是let当您需要类似的东西时,使用会更容易flip f = let g x y = f y x in g

|(图案后卫):

Clean的模式卫士可以像许多其他功能语言一样使用-但是也可以像命令式一样使用if ... else ...。和三元表达式的较短版本。

例如,这些都返回整数的符号:

s n|n<>0|n>0=1= -1
=0

s n=if(n<>0)if(n>0)1(-1)0

s n|n>0=1|n<0= -1=0

当然,最后一个更传统地使用防护的是最短的,但是第一个显示可以嵌套它们(但是在布局规则的同一行上只能出现两个无条件的返回子句),第二个显示了第一个逻辑上做。

一张纸条:

您基本上可以在任何地方使用这些表达式。在lambda表达式,case ... oflet ... in,等。


1

如果您使用的是A String,则应该使用Text

转换为琴弦,以及操纵琴弦({#Char}/ String种类,而不是[Char]种类)非常漫长,不利于打高尔夫球。该Text模块对此进行了补救。

转换:

Text<+为已toString定义的任何两种类型定义运算符。
该运算符的用法与之a<+b相同,即至少toString a+++toString b保存19个字节。即使您包含了额外的导入,,Text并且仅使用了一次,它仍然节省了14个字节!

操作方式:

Text定义了以下缺少的一些字符串操作订书钉StdEnv

  • +字符串的运算符,比+++(from StdEnv)短得多
  • indexOf,具有类似于C的返回-1而不是Nothing失败的行为
  • concat,它连接字符串列表
  • join,它使用分隔符字符串连接字符串列表
  • split,它将字符串分成子字符串上的字符串列表

1

使用较短的lambda

有时您会发现自己使用了lambda表达式(传递给map,或sortBy,等等)。当您执行此操作(编写lambda)时,可以使用多种方法。

正确的方式:

这是sortBy,具有从最长到最短的惯用lambda排序列表

sortBy (\a b = length a > length b)

另一个正确的方法:

如果您使用Data.Func,也可以

sortBy (on (>) length)

简短的方法:

这是同一回事,但是具有更高级的语法

sortBy(\a b=length a>length b)

另一种方法:

这次使用合成并不短,但是有时可以更短

sortBy(\a=(>)(length a)o length)

另一种方式:

虽然这里有些人为设计,但您可以在lambda中使用防护

sortBy(\a b|length a>length b=True=False)

还有节点之前的表达式

sortBy(\a b#l=length
=l a>l b)

一张纸条:

还有另外两种形式的lambda,(\a b . ...)(\a b -> ...),后者与=变体相同,而后者则出于某种原因而存在,并且通常看起来您是在尝试访问某物的属性而不是定义lambda,所以不要不使用它。


1
看到你的一些golfed程序后,我得到的印象\a=... 干净的一贯lambda语法:P
与Orjan约翰森

您还可以在此处使用lambda添加警卫。这是没有记录的(甚至与语言报告相矛盾),但是可以。此外,->=对lambda表达式是相同的,只要编译器而言(->老语法)。只是.有所不同(但我不知道具体如何)。

在此特定示例中,您可以考虑使用on(<)length,尽管Data.Func导入将使您分手,除非您已经需要它。

@基兰酷。我今天晚些时候更新。我认为您也可以#在lambda中使用let-before()。
世纪

是的,您可以:-)

0

使用字符列表文字

字符名单文字是写类似的简写方式['h','e','l','l','o']作为['hello']

这不是表示法的限制,例如:

  • repeat'c'['c','c'..]['cc'..]
  • ['z','y'..'a'] 变成 ['zy'..'a']
  • ['beginning']++[a,b,c]++['end'] 变成 ['beginning',a,b,c,'end']
  • ['prefix']++suffix 变成 ['prefix':suffix]

这些也可以匹配:

  • ['I don't care about the next character',_,'but I do care about these ones!']

0

有时code更短

Clean在标准库中有很多真正有用的功能,其中一些功能在无法访问的情况下难以使用*World,而且*World在代码高尔夫球中使用通常还是个坏主意。

为了解决这个问题,通常ccall可以使用内部code块代替。

一些例子:

系统时间

import System.Time,System._Unsafe
t=toInt(accUnsafe(time))

上面是58个字节,但是您可以使用以下命令保存17个字节(低至40 + 1):

t::!Int->Int
t _=code{ccall time "I:I"
}

随机数

这个不会自行保存字节,但避免了必须从 genRandInt

s::!Int->Int
s _=code{ccall time "I:I"ccall srand "I:I"
}
r::!Int->Int
r _=code{ccall rand "I:I"
}

其他用途

除了这两个(这可能是代码高尔夫球中的主要用法)之外,您还可以调用任何命名的函数(包括但不限于每个syscall),使用嵌入任意程序集instruction <byte>以及为ABC机器嵌入代码。

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.