回答:
import StdEnv
可能な限り避けるアクセスするには組み込み関数、のようにも一見ベーシックなもの(==)
やmap
、import文は通常、必要とされるimport StdEnv
ことが最も一般的なモジュールが好きインポートしているためStdInt
、StdBool
など(参照にここで詳細は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バイト最後のいくつかは実際にバイトを節約する可能性は低いです。なぜなら、直接置換はインポートよりも多くのバイトを生成するからです。
map f list -> [f x\\x<-list] (11 bytes saved)
(または(または同様の))を示すことも役立つかもしれません。
結局のところ、誰もが使用できない言語でゴルフをすることができます!
オンライン
Cleanはよく知られた言語でも文書化された言語でもありません。名前は確かにこれらの問題を解決するために必要なリソースを見つけるのを容易にしません...
クリーンはもともとコンカレントクリーンと呼ばれていましたれ、Cleanに関連するほとんどすべてのドキュメントの序文でまだ使用されています。したがって、Cleanを探している場合は、代わりにConcurrent Cleanを探してください。
CleanのHaskell(その多くがあります)とのより顕著な類似点の1つは、Cloogleの存在です。
局所的に
Cleanに同梱されているライブラリは、IDEを使用して参照できる、適切にコメントされた、ある程度自己文書化されたCleanソースファイルの形式です。
(また、完全なサンプルプログラムが付属してい$INSTALL/Examples
ます。)
そういえば、WindowsバージョンのCleanにはIDEが付属しています。最新の標準ではかなり制限されていますが、テキストエディターとコマンドラインを使用するよりも優れています。
(学習のコンテキストで)最も便利な2つの機能は次のとおりです。
[Ctrl]+[D]
て定義ファイルを開き(または[Ctrl]+[I]
実装ファイルに使用)、定義ファイルと実装ファイルを切り替えることができます[Ctrl]+[/]
Cleanのコンパイラは、ソースファイルを保存したエンコーディングとは関係なく、ファイル内のバイト値だけを考慮します。これにはいくつかのきちんとした結果があります。
ソースコードの本文では、に加えて、印刷可能なASCII文字に対応するコードポイントを持つバイトのみが許可され\t\r\n
ます。
リテラル:
内String
および[Char]
リテラル("stuff"
および['stuff']
それぞれ)、0以外の任意のバイトは、その警告で、許可されている"
と'
(のためにエスケープする必要がありString
、および[Char]
それぞれ)、およびその改行とcarraige戻るしなければならないと置き換えること\n
と\r
(それぞれ)。
ではChar
リテラル、0以外の任意のバイトはその意味を、許可されています:
'\n'
'
'
同じですが、2番目は1バイト短くなっています。
エスケープ:
標準の文字エスケープ\t\r\n
(など)を除き、Cleanのすべての非数値エスケープシーケンスは、スラッシュ、またはエスケープが含まれるリテラルを区切るために使用される引用のいずれかです。
数値エスケープシーケンスの場合、数値は3桁で終了する8進数値として扱われます。つまり、nの後1
にa の文字が続く場合はString
、"\0001"
(または"\0\61"
)を使用する必要があり、ではありません "\01"
。あなたは何でエスケープをたどる場合は、しかし、数字、あなたが先頭のゼロを省略することができます。
結果:
Cleanがソースファイルをどのように処理するかというこの奇妙なことはString
、['Char']
256を超える1桁の数字のシーケンスになることを効果的に可能にします。
関数を定義するとき!@$%^&*~-+=<:|>.?/\
、識別子間の空白を省略することができるため、英数字を使用するよりもいくつかの組み合わせを使用する方が短いことがよくあります。
たとえば、:?a=a^2
はよりも短くf a=a^2
、呼び出しも短くなります。
ただし:
関数識別子が他のシンボルに隣接して使用されている場合、それらは結合して別の有効な識別子を形成できるため、すべて1つの識別子として解析され、エラーが表示されます。
たとえば、次のように?a+?b
解析します? a +? b
さらに:
Cleanでインポートされた識別子を上書きすることが可能であるため、まだ使用されStdEnv
ていない単一文字のシンボル識別子はのみ@$?
です。上書き^-+
(など)は、より多くのシンボリック識別子が必要な場合に役立ちますが、使用している識別子を上書きしないように注意してください。
関数型言語で最も強力な構造(ゴルフ用)の一部は次のとおりlet ... in ...
です。
もちろんきれいで、これがあり、より良いものがあります- #
。
ノードとは何ですか?
Clean's #
およびユビキタス|
(パターンガード)は、どちらも「ノード式」として知られています。
特に、彼らはあなたがimperatively-プログラムできるようっぽいクリーンで(ここでは本当に良いです!)。
#
(レット前):
これらは両方とも文字列として与えられた整数の値を計算し、その文字の合計を乗算します
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
のバージョンがどのように#
短くなり、どのように再定義できるかに注意してください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
もちろん、より伝統的にガードを使用する最後のものが最短ですが、最初のものはネストできることを示しています(ただし、レイアウトルールの同じ行に表示できる無条件のreturn句は2つだけです)。最初は論理的に行います。
注:
これらの式は基本的にどこでも使用できます。ラムダではcase ... of
、let ... in
など、
String
場合は、使用する必要がありますText
文字列への変換、および文字列の操作(種類ではなく{#Char}
/ 種類)は非常に長く、ゴルフには適してString
いません[Char]
。Text
モジュールの救済本。
変換:
Text
定義さ<+
れている任意の2つのタイプの演算子をtoString
定義します。
として使用されるこの演算子a<+b
は、少なくとも19バイトをtoString a+++toString b
節約します。追加のインポートを含めて,Text
1回だけ使用しても、14バイト節約されます!
操作:
Text
から欠落しているいくつかの文字列操作ステープルを定義しますStdEnv
。
+
文字列の演算子。これは+++
(からStdEnv
)よりずっと短いindexOf
、失敗の-1
代わりに戻るというCのような動作Nothing
concat
、文字列のリストを連結しますjoin
、区切り文字列を使用して文字列のリストを結合しますsplit
、文字列を部分文字列の文字列のリストに分割しますラムダ式を使用している場合があります(map
、またはsortBy
などに渡すため)。これを行う(ラムダを書く)とき、それを行う方法はたくさんあります。
正しい方法:
これはsortBy
、慣用的なラムダソートリストを最長から最短に並べたものです
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)
他の方法:
ここでは少し工夫されていますが、ラムダでガードを使用できます
sortBy(\a b|length a>length b=True=False)
また、let-beforeノード式
sortBy(\a b#l=length
=l a>l b)
注:
2つのがあり、よりラムダのフォーム、あり(\a b . ...)
と(\a b -> ...)
同じとなっている、後者=
の変異体は、およびそのうちの前者は、何らかの理由で存在し、多くの場合、あなたが何かのプロパティにアクセスしようとする代わりに着るので、ラムダを定義しているように見えます使用しないでください。
\a=...
を受けました:P
->
そして=
ラムダのために限りコンパイラが懸念しているものと同一です(->
古い構文です)。.
異なるだけです(しかし、私は正確にどのように知りません)。
#
ラムダでlet-before()も使用できると思います。
文字リストのリテラルは次のようなものを書くの簡略な方法である['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!']
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"
}
その他の用途
おそらくcode-golfでの主な用途であるこれら2つに加えて、任意の名前付き関数(すべてのsyscallを含むがこれに限定されない)を呼び出し、で任意のアセンブリをinstruction <byte>
埋め込み、ABCマシンのコードを埋め込むことができます。
import StdEnv
+a and b
(21バイト)は%[a:r]|a= %r=a;%_=True
(22バイト)より小さくありませんか?または、import StdEnv
+a=True and b=True
(31バイト)になりますが、その場合は実際に確実に短くなりますか?(私はところで、クリーンでプログラムたことがありません。)