Clean'te golf için ipuçları


17

Clean'te golf oynamak için hangi genel ipuçlarınız var? Lütfen sadece golf problemlerini genel olarak kodlamak için uygulanabilecek ve en azından biraz Clean'e özgü fikirleri gönderin.

Clean'i daha önce hiç duymadıysanız, burada daha fazla bilgi edinebilirsiniz .
Veya sohbet odasına katılabilirsiniz .

Yanıtlar:


10

import StdEnvMümkün olduğunca kaçının

Erişmek için yerleşik işlevleri, hatta görünüşte temel olanları gibi (==)ya map, bir ithalat beyanı genellikle gereklidir import StdEnven yaygın modüller gibi ithal çünkü StdInt, StdBoolvb (bkz burada detaylı bilgiler için StdEnv).

Ancak, bazı zorluklar için bu içe aktarma işleminden kaçınmak ve sadece liste kavrayışı ve kalıp eşleştirme gibi temel dil özelliklerini kullanmak mümkün olabilir.

Örneğin,

import StdEnv 
map f list

biri yazabilir

[f x\\x<-list]

Alternatiflerin listesi:

İhtiyaç duyulan bazı işlevler veya işlev çağrıları import StdEnv, içe aktarma gerektirmeyen bir alternatif ve kaydedilen baytların kaba bir tahmini.

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

Son birkaçının baytları kaydetme olasılığı düşüktür, çünkü doğrudan değiştirme, içe aktarmadan daha fazla bayt verir, ancak liste üzerinde yinelemenin gerekli olduğu durumlarda mümkün olabilir.

Bu ipucu burada başarıyla kullanıldı .


Peki import StdEnv+ a and b(21 bayt) %[a:r]|a= %r=a;%_=True(22 bayt) ' dan küçük değil mi? Yoksa import StdEnv+ a=True and b=True(31 bayt) olur, bu durumda kesinlikle daha kısadır? (Clean,
btw'de

@KevinCruijssen Bunu sadece sohbette tartışıyorduk . Bunların bayt kaydetme olasılığı düşüktür, ancak program yine de bir liste üzerinde geri çekilmek zorunda olduğunda.
Laikoni

4
Ah tamam. Alternatif ile kaç bayt kaydedildiğini belirtmek de yararlı olabilir (yani map f list -> [f x\\x<-list] (11 bytes saved)(veya benzer bir şey)).
Kevin Cruijssen

@KevinCruijssen Tamamlandı.
Laikoni

5

Dili nasıl öğreneceğinizi öğrenin

Sonuçta, herkes kullanamayacağı bir dilde nasıl golf oynayabilir?

İnternet üzerinden

Temiz, iyi bilinen veya iyi belgelenmiş bir dil değildir ve adı, bu sorunları gidermek için çok ihtiyaç duyulan kaynakları bulmayı kesinlikle kolaylaştırmaz ... ya da öyle mi?

Clean başlangıçta Clean ile ilgili hemen hemen her belgenin önsözünde kullanılan Concurrent Clean olarak adlandırıldı - bu yüzden Clean arıyorsanız, bunun yerine Concurrent Clean'i arayın.

Clean'in Haskell ile daha çok benzerlik gösteren özelliklerinden biri (çoğu var), Clean'in birlikte geldiği kütüphaneleri kapsayan bir fonksiyon arama motoru olan Cloogle'ın varlığıdır .

lokal olarak

Clean ile birlikte gelen kütüphaneler, IDE kullanılarak göz atılabilen, iyi yorumlanmış, biraz kendi kendini belgeleyen Temiz kaynak dosyaları şeklindedir.
(Ayrıca tam örnek programlar ile birlikte gelir $INSTALL/Examples.)

Bundan bahsetmişken, Clean'in Windows sürümü bir IDE ile geliyor - modern standartlarla oldukça sınırlı olsa da, bir metin editörü ve komut satırı kullanmaktan daha iyi.
En yararlı iki özellik (öğrenme bağlamında):

  • Hangi satırda olduğunu görmek için bir hatayı çift tıklayabilirsiniz
  • Bir modül adını vurgulayabilir ve [Ctrl]+[D]tanım dosyasını açmak (veya [Ctrl]+[I]uygulama dosyası için kullanmak) için düğmesine basabilir ve tanım ile uygulama dosyası arasında geçiş yapabilirsiniz.[Ctrl]+[/]

4

Karakter kodlamasını unutun

Clean'in derleyicisi, kaynak dosyayı kaydettiğinizi düşündüğünüz kodlamayı, dosyadaki bayt değerlerini önemsemez. Bunun bazı düzgün sonuçları var.

Kaynak kodun gövdesinde, yalnızca yazdırılabilir ASCII karakterlerine karşılık gelen kod noktaları olan baytlara ek olarak bunlara da izin verilir \t\r\n.

Değişmez:

Gelen Stringve [Char]değişmezleri ( "stuff"ve ['stuff']sırasıyla), 0 dışında bir bayt bu uyarı ile, izin verilir "ve '(için öncelenmelidirler Stringve [Char]sırasıyla) ve bu satırların ve carraige döner şart ile değiştirilmesi \nve \r(aynı zamanda, sırasıyla).

Gelen Chardeğişmezleri, 0 dışında herhangi bir bayt , yani izin verilir:

'\n'

'
'

Aynı, ancak ikincisi bir bayt daha kısadır.

kaçan:

Standart mektubun dışında kaçar \t\r\n (vb.) , Clean öğesindeki tüm sayısal olmayan kaçış dizileri ya eğik çizgi için ya da kaçışın içindeki değişmez değeri sınırlamak için kullanılan tırnak içindir.

Sayısal kaçış dizileri için, sayı üç basamaktan sonra sonlandırılmış bir sekizlik değer olarak ele alınır. Eğer karakteri tarafından takip bir null istiyorsanız bu araçlar o 1bir de String, kullanılan gerekir "\0001"(veya "\0\61") ve değil "\01" . Ancak, herhangi bir şeyle kaçış izlerseniz ancak numaraları, bundan önce gelen sıfırları atlayabilirsiniz.

Sonuçlar:

Clean'in kaynak dosyalarını nasıl işlediğiyle ilgili bu tuhaflık, kod-golf için dizinleri depolamak gibi çok sayıda kullanımı olan (tabii ki 255'e kadar) temel-256 tek basamaklı sayıların dizilerine izin verir Stringve ['Char']etkili bir şekilde olur.


3

Sembollü isim fonksiyonları

Bir işlevi tanımlarken, !@$%^&*~-+=<:|>.?/\alfasayısal karakterleri kullanmaktan daha fazla bir kombinasyon kullanmak genellikle daha kısadır , çünkü tanımlayıcılar arasındaki beyaz boşluğu atlamanıza izin verir.

Örneğin: ?a=a^2daha kısadır f a=a^2ve çağırmak da daha kısadır.

Ancak :

İşlev tanımlayıcısı, farklı ancak geçerli bir tanımlayıcı oluşturmak için birleştirilebilen diğer simgelerin yanında kullanılırsa , bunların tümü tek bir tanımlayıcı olarak ayrıştırılır ve bir hata görürsünüz.

Örnek: ?a+?bolarak ayrıştırmak? a +? b

Bunlara ek olarak:

Zaten kullanılmaz sadece tek karakterlik sembol tanımlayıcıları yüzden Clean ithal tanımlayıcıları üzerine yazmak mümkündür ve StdEnvvardır @$?. ^-+Daha fazla sembolik tanımlayıcıya ihtiyacınız varsa üzerine yazma (vb.) Yararlı olabilir, ancak kullandığınız kodun üzerine yazmamaya dikkat edin.


3

K düğümlerinizi tanıyın

İşlevsel dillerdeki en güçlü yapılardan bazıları (golf için) let ... in ....
Temiz tabii ki, bu, ve daha iyi bir şey - #.

Düğüm nedir?

Clean'ler #ve her yerde bulunan |(desen koruması) her ikisi de 'düğüm ifadeleri' olarak bilinir.
Dikkat çekici bir şekilde, Temiz'de (bu gerçekten iyi!) Zorunlu olarak programlamanıza izin verir .

#(Let-öncesi):

Her ikisi de dize olarak verilen bir tam sayının değerlerini, karakterlerinin toplamıyla çarpımını hesaplar

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ürümünün nasıl #daha kısa olduğuna ve nasıl yeniden tanımlayabileceğimize dikkat edin s. Bu, bir değişkenin aldığımızda sahip olduğu değere ihtiyacımız olmadığında kullanışlıdır, bu nedenle adı tekrar kullanabiliriz. ( letbunu yaptığınızda sorunlarla karşılaşabilirsiniz)

Ama letböyle bir şeye ihtiyacınız olduğunda kullanmak daha kolayflip f = let g x y = f y x in g

|(Pattern guard):

Clean'in desen koruyucusu diğer birçok işlevsel dilde olduğu gibi kullanılabilir - ancak bir zorunluluk gibi de kullanılabilir if ... else .... Üçlü ifadenin daha kısa bir versiyonu.

Örneğin, bunların hepsi bir tamsayının işaretini döndürür:

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

Tabii ki, muhafızı daha geleneksel kullanan en kısa olanıdır, ancak birincisi onları yuvalayabileceğinizi gösterir (ancak düzen kuralında aynı satırda sadece iki koşulsuz dönüş cümlesi görünebilir) ve ikincisi, birincisi mantıklı.

Bir not:

Bu ifadeleri temelde her yerde kullanabilirsiniz. Lambdas yılında case ... of, let ... invb


1

Bir Stringkullanıyorsanız,Text

Dizelere dönüşüm ve dizelerin manipülasyonu ( {#Char}/ Stringtür, tür değil [Char]) golf için oldukça uzun ve kötüdür. TextModül ilaçları bu.

Dönüştürmek:

Texttanımlanan <+iki tür için operatörü tanımlar toString.
Bu operatör, en az 19 bayt tasarruf ilea<+b aynı şekilde kullanılır . Ekstra içe aktarmayı dahil etseniz ve yalnızca bir kez kullansanız bile, yine de 14 bayt tasarruf sağlar!toString a+++toString b,Text

Oynama:

Texteksik olan bir dizi dize düzenleme zımba tanımlar StdEnv:

  • Operatör +çok daha kısadır dizeleri, +++(dan StdEnv)
  • indexOf, başarısızlık -1yerine C benzeri dönme davranışı ileNothing
  • concat, dizelerin listesini birleştirir
  • join, bir ayırıcı dize kullanarak dizelerin bir listesini birleştirir
  • split, bir dizeyi bir alt dize üzerindeki dizeler listesine böler

1

Daha kısa lambdalar kullanın

Bazen kendinizi lambda ifadesi kullanarak bulursunuz ( mapveyasortBy , vs.). Bunu yaparken (lambdalar yazarken) bunu yapmanın bir çok yolu vardır.

Doğru yol:

Bu, sortByen uzuntan en kısa bir deyimsel lambda sıralama listesiyle

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

Diğer doğru yol:

Kullanıyorsanız Data.Func, şunları da yapabilirsiniz

sortBy (on (>) length)

Kısa yol:

Bu aynı şey, ama daha golf sözdizimi ile

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

Diğer yol:

Kompozisyon kullanmak bu sefer daha kısa değil, ancak bazen daha kısa olabilir

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

Diğer yol:

Burada biraz çelişkili olsa da, lambdalarda koruma kullanabilirsiniz

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

Ve ayrıca izin vermeden önce düğüm ifadeleri

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

Bir not:

İki tane daha lambda formu vardır (\a b . ...)ve (\a b -> ...)bunların ikincisi =varyantla aynıdır ve ilki bir nedenden ötürü vardır ve genellikle bir lambda tanımlamak yerine bir şeyin özelliğine erişmeye çalışıyorsunuz. kullanma.


1
Senin golfed programların bazıları gördükten sonra izlenim var vardı \a=... oldu Clean her zamanki lambda sözdizimi: P
Ørjan Johansen

Ayrıca burada kullanıldığı gibi korumaları lambda'ya da ekleyebilirsiniz . Bu belgelenmemiş (dil raporuyla bile çelişiyor), ama işe yarıyor. Ayrıca, ->ve =lambdas için kadarıyla derleyici söz konusu olduğunda aynıdır ( ->eski sözdizimi). Sadece .farklı (ama tam olarak nasıl olduğunu bilmiyorum).

Ve bu özel örnekte on(<)length, Data.Funciçe aktarma işlemi zaten gerekmedikçe sizi ayıracak olsa da kullanmayı düşünebilirsiniz .

@Keelan Cool. Bunu bugün daha sonra güncelleyeceğim. Sanırım #lambdalarda let-before ( ) kullanabilirsiniz .
Οurous

Evet, şunları yapabilirsiniz :-)

0

Karakter Listesi Değişmezlerini Kullan

Bir karakter listesi değişmezi gibi bir şey yazmaya bir stenografi yoludur ['h','e','l','l','o']olarak ['hello'].

Gösterimin sınırı bu değildir, örneğin:

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

Bunlar da eşleştirmede çalışır:

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

0

Bazen codedaha kısa

Temiz bazıları erişimi olmayan kullanımına ayrıntılı inanılmaz olan, standart kütüphanelerde gerçekten yararlı fonksiyonları bir grup var *Worldve kullanma*World kod golf zaten genellikle kötü bir fikirdir.

Bu sorunun üstesinden gelmek için, genellikle blokların ccalliçinde kullanabileceğiniz s vardır code.

Bazı örnekler:

Sistem zamanı

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

Yukarıdaki 58 bayttır, ancak 17 bayt (40 + 1'e kadar) kaydedebilirsiniz:

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

Rastgele sayılar

Bu, baytları kendi başına kaydetmez, ancak bir listenin içinden geçmek zorunda kalmaz genRandInt

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

Diğer kullanımlar

Büyük olasılıkla kod golfde bunun ana kullanımları olan bu ikisine ek olarak, adlandırılmış herhangi bir işlevi çağırabilir (her sistem araması dahil ancak bunlarla sınırlı olmamak üzere), instruction <byte>ABC makinesiyle keyfi birleştirme gömebilir ve kodu ABC için gömebilirsiniz.

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.