Prolog'da golf için ipuçları


16

Prolog'da golf oynamak için hangi genel ipuçlarınız var? Ben genel olarak en azından biraz Prolog (örneğin bir harf değişkenleri programların boyutunu azaltmak için Prolog için spesifik değildir) kod golf sorunları uygulanabilecek fikirler arıyorum.

Lütfen Prolog uygulamasına özgü olup olmadığını ipuçlarınızda belirtin (örn. SWI-Prolog'a özel yerleşikler)

Lütfen her yanıt için yalnızca bir ipucu veya aynı ana fikirle yakından ilişkili bir ipucu listesi gönderin.


1
prologEtiket tür işe yaramaz. Bir Interpret Prolog mücadelemiz olmadığı sürece buna ihtiyacımız yok.
kedi

Yanıtlar:


11

Tahmin İsimleri için İşleçleri Kullanma

Operatör önceden tanımlanmış operatörlerden ( burada listelenen ) biri olduğu ve halihazırda bir yüklem olarak tanımlanmadığı sürece operatörlere isimler olarak tahmin vermek mümkündür . Bu, yüklemi tanımlarken ve çağırırken birkaç bayt kazandırır çünkü operatör tahminlerinin normal name(arg1,arg2,etc..)biçimde yazılmasına gerek yoktur ve operatörlerden beklendiği gibi çağrılabilir.

Bir ve iki argüman öngörüsü için, sırasıyla tekli ve ikili operatörlerin adlarını verebilirler. Yüksek arity tahminleri için, desen eşleştirmeyi kullanarak parantezlerden kaçınabiliriz. Örneğin;A+B+C:-... , Prolog onun kullanacağı operatör öncelik ve etkinlikleri kurallarını dönüştürmeye (A+B)+C:-...hangi ilk argüman desen eşleşen bir operatör yüklem olduğu A+B. Ya da A-B+C*D:-...bir hale geldiği (A-B)+(C*D)ilk bağımsız değişkeni ile eşleşen bir yani A-Bve ikinci desen ile eşleştirilir C*D.

Örnekler

_+_+_.
A-B+C*D:-between(A,B,C),C+D.
\X:-X>1,X<10.
X+Y:-length(Y,X),member(X,Y).



5+[10,5,3,2,5],a+b+c,0-20+X*[2,4,6,5,40],\9.

Çıktı X = 5.

Çevrimiçi deneyin!

sonuç

DCG'lerden beri yüklemler için sözdizimsel şeker vardır onlar da adları için operatörler verilebilir. Bu, bir DCG'den DCG'ler olarak adlandırılırken veya phraseDCG'lerle çalışmak üzere tasarlanmış yüklemleri veya diğerlerini kullanırken beklendiği gibi çalışır . DCG tahminleri fark listeleri için ek iki argüman aldığından, bunları A+B-->...tahmin olarak çağırırken parantez gereklidir (örn. Gibi çağrılmalıdır +(A,B,...)). Operatör kalıbı eşleşmesini kullanan ikiden fazla bağımsız değişkeni olan DCG adındaki operatör için, kalıpla eşleşen işleçlerin doğru dağıtıldığını belirten bir değer olarak adlandırıldığından emin olmak önemlidir.

Ek argüman almayan DCG'lere operatör adları vermek, bunları programınız içinde çağırmanız gerektiğinde yararlı olabilir, çünkü o zaman parantez kullanmadan bunu yapabilirsiniz. Dikkat edilmesi gerekir, çünkü parantez içinde kaydettiğiniz şey, bitişik işleçleri ayrıştırmak için gereken ek boşluğa kaybedebilirsiniz.

Örnekler

/ -->a+b+X,X+d+e.
A+B+C-->[A],[B],[C].


X/[],member(c,X),phrase(f+o+o,Y),+(b+a,r,Z,[]).

Çıktı

X = [a, b, c, c, d, e],
Y = [f, o, o],
Z = [b, a, r].

Çevrimiçi deneyin!

Uyarılar

Tekli operatörler +ve -Prolog ile bir veya yüklem çağrısı yerine +20veya -20sayı olarak yorumlayacaktır . Tekli veya ad olarak verilen tahminler parantez ( , ) kullanılarak hala numaradan çağrılabilir . Parantezlerden fazladan baytlardan kaçınmak isteniyorsa, diğer tekli operatörler ,+/1-/1+-+(20)-(20)\$ vb yerine adlar olarak kullanılabilir.

Örüntü eşleme ve isimlendirilmiş tahminler kombinasyonu tamamen kusurlu değildir. İsimleriyle aynı operatöre sahip olan ve desen eşleştirme ile diğerine göre daha genel olan iki tahmininiz varsa, daha genel olan ilk önce çağrılabilir veya daha az genel olan başarısız olursa (kaynaktaki siparişlerine bağlı olarak) . Örneğin yukarıdaki örnekte A-B+C*Dgirdisiyle eşleşmezse, Prolog aramayı dener X+Y. Bu bir hatayla sonuçlanır, çünkü formda olacağı için olmayacağı bir tamsayı olmasını length/2gerektirir . Bu, hiçbir iki tahminin adıyla aynı operatöre sahip olmadığından emin olunarak veya bu başarısız olursa, kaynağın kesilmelerini ve dikkatli sıralanmasını kullanarak önlenebilir.YC*D


3
Bu hile kod golf için ne kadar yararlı şaşırtıcı. Sadece bu ipucunu kullanarak bir yanıtın bayt sayısını% 16 azalttım!
DLosc

7

Olası her durumu tek bir kurala yerleştirmeye çalışın

Prolog'da programlamanın temiz yolu, aynı yüklem için birden fazla kural bildirmektir. Örneğin, bir akümülatörlü bir listeyi tersine çevirme öngörüsü şöyle görünecektir:

r([],Z,Z).
r([H|T],Z,R):-r(T,[H|Z],R).

Code-golf'de, birinci kuralı kaldırabilir ;ve özyineleme sonunu kodlamak için ikinci kuralın sonuna a ekleyebiliriz :

r([H|T],Z,R):-r(T,[H|Z],R);R=[H|Z].

İlk koşulun r(T,[H|Z],R)T'nin boş olması durumunda başarısız olacağını , yani özyinelemenin bitmesi gerekiyorsa ve böylece sonlandırmamızı ondan sonra bir veya yan tümcesi olarak ekleyebiliriz.

Aynı ilke birçok durumda işe yarar. Bununla birlikte, bazen bunu yapmak yerine başka bir kural beyan etmenin daha kısa olduğunu unutmayın.


7

Tuple yapıcıları ve eksileri olarak aritmetik işleçleri kullanma

İki veya daha fazla değerden oluşan tek bir yapıyı geçmeniz gerekiyorsa, kullanılacak en belirgin şey bir listedir, örn. [A,B] . Yine de bu çok ayrıntılı.

Bir alternatif var. Prolog değerleri, değerlendirilmeyen oldukça keyfi bir iç içe yapı saklayabilir. Bunun nasıl çalıştığını gösteren bir örnek:

| ?- member(member(A,B),C).
C = [member(A,B)|_] ? ;
C = [_,member(A,B)|_] ? ;
(etc.)

member(A,B) bu durumda sadece adlandırılmış bir demet ve dış member (bir işlev çağrısıdır) ona böyle davranır.

Adlandırılmış tuples, golf oynamamış Prolog programlamasında oldukça yararlı olsa da, liste yaklaşımından daha ayrıntılı görünebilirler. Bununla birlikte, tuple yapıcısının adında hemen hemen rastgele karakterler kullanabiliriz (düzgün bir şekilde alıntılandıklarını varsayarak); sevimli memberbir şey ya da tek bir karakter yerine, böyle bir aşey yapabiliriz:

| ?- A = '-'('/'(1,2), '/'(3,4)).
A = 1/2-3/4

Burada, tuple yapıcılarımız '-'ve '/'. Ve güzel yazıcının onlarla ne yaptığını not etmek ilginç; tuples için infix gösterimi kullanıyor . Bu gerçekten kesiktir ve karşılaştırılabilir aritmetik işlemle aynı şekilde ayrıştırılır. (Aritmetik kullanımları nedeni de açıklıyor isdeğil =; A = 1+2birleştirecek Aolan başlığın '+'(1,2) tuple yapıcı çağrılacak Çünkü böylece ayrı sözdizimi aslında unevaluated aritmetik ifade değerlendirmek için gereklidir.) Bir şey , siz de kısa ve öz olan bir karakter kullanabilir sözdizimi (ve bonus olarak -ve/anlamlı olmayan bir şeyden ziyade aynı şekilde, hızlı bir takas tuple yapıcısı istediklerinde golf dışı koddaki en yaygın seçeneklerden bazılarıdıri genellikle bir döngü değişkeni olarak kullanılır, bu nedenle orada herhangi bir nedenle bir demet istiyorsanız, giriş ve çıkışlarınızda kullanmak tamamen mantıklıdır).

'-'ve '/'tuple kurucuları için iyi seçimlerdir, çünkü tuple değişmezlerini ters yazmanıza izin veren iyi davranışlı ve kullanışlı önceliğe sahiptirler. Ancak, programın içinde ara değerler üretilirken öncelik konusunda endişelenmenize gerek olmadığını unutmayın. Prolog, kodları kaynak kodu yerine ağaç olarak saklar ve güzel yazıcılar bunu net bir şekilde çıktılar:

| ?- A = '-'('-'(1,2), '-'(3,4)).
A = 1-2-(3-4)

Tanımlama grubu sözdizimi terse böylece olduğundan ( f(A,B)daha kısadırf(A-B) ) olduğundan, birden fazla tahmin argümanını ücretsiz olarak tuples ile değiştirebilirsiniz, yani bir yüklemin iki veya daha fazla argümanını başka bir yükleme geçirmesi gerekiyorsa, bunları genellikle bir demet ve sadece demet geçirin (bu, yüklemin kendisine ek olarak uygun bir demet yapıcıları ve virgül karışımı kullanmak için yükleme yapılan tüm çağrıları değiştirmeyi gerektirse de).

Bu sözdiziminin bir diğer avantajı, listeleri dahili olarak kullanmanız gerektiğidir (standart tahminlerle birlikte çalışmak yerine); bir liste temel olarak sadece iç içe eksilerini içeren bir kümedir ve eksileri hücre, '.'burada görülebileceği gibi, yapıcı içeren bir demettir :

| ?- Q = '.'('.'(A,B),'.'(C,D)).
Q = [[A|B],C|D]

Kodunuz "el ile" listeleri kullanıyorsa, daha az hacimli bir grup yapıcısı kullanmak mantıklı olabilir '.'. Benim için ortak bir seçim bir eksilerini temsil etmektir '/'(Tail,Head)(çünkü karakter israf etmeden hata ayıklama çıktısında alabileceğiniz en okunaklı hakkındadır). Muhtemelen kendi []eşdeğerinizi de isteyeceksiniz ; Eğer olabilir kullanmak[] ama uzun iki bayt olduğunu ve bunun yerine kullanabileceğiniz tek baytlık atomları (tümü küçük harf) bol vardır.

Örneğin, aşağıdaki liste:

[1,2,3]

bunun gibi aynı sayıda karakterde manuel temsile dönüştürülebilir:

x/3/2/1

[H|T]-senin örüntü eşleşmelerinin artık daha tersine yazılabilmesi T/Hve boş listeye xdaha uzun değil , bir testin yazılması avantajını elde etmek []. (Elbette, bu bariz dezavantajını da beraberinde member, appendvb bu temsilin çalışmaz.)


1! -Ve kullanılırken tek tırnak işareti kullanılmasına gerek yoktur /. Bunlar zaten normal atomlar.
mat

Ve, .aşağıdaki karakterlerin %ne bir düzen ne de bir düzen olması şartıyla, etrafında tek tırnaklara gerek yoktur .
yanlış

6

Sık kullanılan bir hile: Birkaç yönde otomatik olarak kullanılabilen tahminler elde etmek için tamsayı aritmetiği için CLP (FD) kısıtlamalarını kullanın , böylece koşullardan ve özel dallardan ve varyantlardan kaçınır.

B-Prolog veya GNU Prolog kullanın, bu tür kısıtlamaların kütüphaneden yüklenmesine gerek kalmadan kutudan çıkar çıkmaz.


2
Bu, burada zorluklar yaparken SWI-Prolog ile her zaman nefret ettiğim bir şey. CLPFD kullanmak bazı şeyleri çok daha temiz ve daha kısa hale getirecektir, ancak genellikle işe yaramayacak bir sürü ekstra kod eklemelisiniz (genellikle dahil etmek çok fazla ...). Sanırım bunu sadece bu cevapta kullandım .
16:44

3
Bundan da nefret ediyorum ve kesin library(clpfd)olarak SWI-Prolog'da önceden yüklenmiş veya en azından otomatik olarak yüklenmiş bir kütüphane olarak ne zaman kullanılabilir olacağı zamanın geleceği kesin . Deklaratif aritmetik, eski, düşük seviyeli özelliklerle onlarca yıllık deneyime sahip olan tüm kullanıcılar tarafından tamamen anlaşılmaya ve takdir edilmeye kadar birkaç yıl sürebilir. CLP'yi (FD) ne kadar çok kullanır ve savunursanız, varsayılan olarak o kadar çabuk alırız. O zamana kadar, sadece koyabilirsiniz :- use_module(library(clpfd)).senin içinde ~/.swiplrcsen SWI-Prolog o "varyantı" kullandığınızı ve adil devlet.
mat

5

Liste listeleri için daha kısa sözdizimi ve haritaları bildirmenin bir yolu

Baytları liste listelerine kaydedebilirsiniz. Bir listeniz varsa [[1,2],[3,4]], bunu aslında [1:2,3:4]4 parantez = 4 bayt kaydeden olarak ilan edebilirsiniz . Başka bir şey kullanabileceğinizi unutmayın :(örneğin, ^).

1:2aslında bu durumda bir liste değildir (oysa [1,2]), dahili olarak temsil edilir :(1,2). Bu nedenle, iki nokta üst üste kullanan bu alt listelerdeki listelerde çalışan tahminleri kullanamazsınız.

Bu hile esas olarak haritaları bildirmek için kullanılır, yani değerlere eklenmiş anahtarların bir listesi. Örneğin, Mhem İngilizce hem de Fransızca bir rakam yazımını içeren bir harita bildirmek isterseniz , şöyle bir şey yapabilirsiniz:

M=[0:'Zero':'Zéro',1:'One':'Un',2:'Two':'Deux', ... ]

Daha sonra örneğin yerleşik bir yüklem ile haritanın öğelerini alabilirsiniz member/2. Eğer karşılık gelen rakam ve İngilizce kelime istiyorsanız Örneğin, 'Quatre'içinde M, bunu yapabilirsiniz:

member(Digit:Name:'Quatre',M).

1
Bunu genelleştirebilirsiniz. Örneğin, wirte edebilirsiniz [[1,2],[3,4]]olarak 1*2+3*4hangi +(*(1,2),*(3,4))ve böylece de aksi açılış ve kapanış parantez için, iki gerekir tek bayt kullanır.
mat

Çift tırnak listeleri daha da kısa şunlardır: "abc"yerine içinde[a,b,c]
yanlış

5

Bir düzgün hile: Başarısız olmanız gerektiğinde , false / 0'a eşdeğer , ancak daha kısa bir şey kullanın  , örneğin:

? - tekrarla, writeln (hi), 0 = 1 .

3
Zorunlu Prolog Sanatı alıntısı: " Prolog programlamasında (belki de genel olarak yaşamın aksine) amacımız mümkün olduğunca çabuk başarısız olmaktır ". Eğlenceli bir gerçek: Ayrıca kullanabilirsiniz \+!3 gerçekte kesim tetikler etmeyen başarısız olmasına garip bir şekilde bayt olarak !(bkz bu için neden ). 3 bayttan daha az bir sürede başarısız olmanın mümkün olduğunu düşünmüyorum.
50'de ölümcül

Bunu yazarken de bu alıntıyı düşünüyordum ;-)
mat

2
Gerçekten her iki versiyona da ihtiyacımız var \+!, soldaki diğer grafik karakterlere 0=1tutkallar, isimler için soldaki tutkallar.
yanlış

5

Bir yüklemi farklı arama modlarıyla tekrar kullanma

Örneğin, aynı yükleme sahip bir yapıyı, bir kez değişken argümanla ve başka bir kez de temel terim ile ayrıştırabilir ve yazdırabilirsiniz. Bu yaklaşımı Sıkı Yılanlar Öpücüğü Yap'ta kullandım . Bu elbette tüm zorluklarda mümkün değildir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.