プロローグ(SWI) 、134の 128 127 124バイト
この答えは、私と0 'のコラボレーションの一部です。私たちは一緒にこれに取り組みましたが、私がそれを投稿している唯一の理由は、私がRock、Paper、Scissorsに勝ったからです。
\Q-->{Q=1};"(",\N,")",\B,{findnsols(N,I,(between(2,inf,I),\+ (between(3,I,U),0=:=I mod(U-1))),L)->append(_,[Y],L),Q is Y*B}.
オンラインでお試しください!
説明
この答えは、プロローグでのゴルフを楽しいものにする完璧な例です。
この答えは、明確な節の文法にPrologsの強力なシステムを使用しています。ここに、少しだけ文法があります。
head(1)-->[].
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
prime(N,Y):-
findnsols(N,I,(
between(2,inf,I),
isprime(I)
),L),
append(_,[Y],L),!.
最初の構築規則は次のとおりです。
head(1)-->[].
これは、空の文字列が1に対応することをPrologに伝えます。
構築の2番目のルールは、もう少し複雑です。
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
これは、空でない文字列には、これらの同じ規則を持つ句の右側、これらの同じ規則を持つ句の右側に括弧が含まれることを示しています。
また、この句の値(Q
)が規則に従っていることもわかります。
{prime(N,Y),Q is Y*B}
これを分解すると、Q
2つの数字Y
との積になりB
ます。 B
左側の句の値だけで、Y
あるN
番目プライムN
カッコ内の句の値です。
このルールは、因子ツリーの両方の形成ルールをカバーします
- 連結乗算
- エンクロージャーはn番目のプライムを取ります
次に、述語定義について説明します。改変されていないバージョンには2つの述語があります(私の実際のコードでは、述語を前方に連鎖させています)。ここでの2つの関連する述語はisprime/1
、素数に一致する、およびprime/2
、与えられたN
、およびY
に一致する場合に一致するiff Y
がN
th番目の素数である場合です。最初に
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
これは、素数性の非常に標準的な定義で機能します。2をI
含む2を含むが、I
その除算は含まないと主張しI
ます。
次の述語も非常に簡単です
prime(N,Y):-
findnsols(N,I,(
between(2,inf,I),
isprime(I)
),L),
append(_,[Y],L),!.
素数でfindnsols
ある最初のN
数を見つけるために使用し、最後の数を返します。ここでのコツは、SWIが処理する方法のために常に最小の素数findnsols
を見つけることが保証されない一方で、常により小さな素数をより早く見つけることです。ただし、これは、より多くの素数を見つけられないようにカットする必要があることを意味します。 N
between
ゴルフ
コードで理由を2回転送できます。isprime
は定義が内に移動できる場合にのみ使用されるためですprime
。次prime
は、DCGの内部に直接移動することですが、カットインを使用して素数が多くなりすぎprime
ないようにするためfindnsols
、少し問題があります。カットは、必要なビットだけではなく、DCG全体をカットします。ドキュメントを少し掘り下げた後、once/1
DCG全体ではなく、この部分のみをカットするために使用できることがわかりました。しかし、文書をさらに掘り下げてみると、->
オペレーターを使用して同様のタスクを実行できることも明らかになりました。->
オペレータはほぼ同等である,!,
我々は、他の側に私たちのカットを移動してappend/3
し、それを置き換えます->
。
SWI-Prologでは、述語(および規則)に演算子を名前として付けることができます。これにより、通常必要な括弧を削除できます。これにより、ルールを呼び出すことで6バイトを節約できます\
。