val()=hd[(fn s=>let val$ =s^"\""^String.toString s^"\"]"val(189,%)=(size$,$)in print%end)"val()=hd[(fn s=>let val$ =s^\"\\\"\"^String.toString s^\"\\\")\"val(189,%)=(size$,$)in print%end)"]
Çevrimiçi deneyin!
MLton için, tam SML programları ya ;
(örn. print"Hello";print"World";
) İle sınırlandırılmış ve sonlandırılmış ifadeler ya da var
ve fun
anahtar kelimelerle (ör.var _=print"Hello"var _=print"World"
) _
ayrıca herhangi değişken adı ile değiştirilebilir olabilir vahşi karttır.
İlk seçenek, bozulmamış programlama için işe yaramaz çünkü ;
kendi başına geçerli bir programdır (hiçbir şey yapmaz, ancak hata yapmaz). İkinci yaklaşımla ilgili sorun, benzer beyanların var _=print"Hello"
sadece var _="Hello"
(hattavar _=print
)var
, sağ tarafın geçerli bir SML ifadesi veya değeri (SML işlevsel bir dildir, bu nedenle işlevler olabileceği sürece) gibi değer olarak da kullanılır).
Bu noktada, tesadüfen desen eşleştirme üzerine tökezlediğimde , val
SML'de bozulmamış programlamayı imkansız ilan etmeye hazırdım . Beyanlar için sözdiziminin val <variable_name> = <expression>
değil val <pattern> = <expression>
, bir desenin değişken isimlerden, sabitlerden ve yapıcılardan oluşabileceği ortaya çıkıyor. Gibi print
işlev türü vardır string -> unit
, biz bir desen eşleşmesini kullanabilirsinizunit
-değer ()
baskı fonksiyonu aslında dize uygulanan zorunlu kılmak amacıyla: val()=print"Hey"
. Bu yaklaşımla, birini kaldırmak print
veya "Hey"
bir Pattern and expression disagree
hataya neden olur.
Elimizdeki bu bozulmamış baskı ile bir sonraki adım, son olarak biraz daha fazla korumaya ihtiyaç duyulmadan önce bir quine yazmaktır. Daha önce kolay bir SML quine tekniği kullandım ( revizyon geçmişine bakın ), ancak Anders Kaseorg davasında bazı baytları kurtarabilecek farklı bir yaklaşıma dikkat çekti. String.toString
Dize çıkışını işlemek için yerleşik işlevi kullanır ve genel biçimdedir<code>"<data>"
, burada "<data>"
öncekinden kaçan bir dize code
:
val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"
Bu çalışan bir kine ama henüz bozulmamış. Her şeyden önce Anders Kaseorg, MLton'un tek bir teklifi kabul ettiğini öğrendi"
hata üretmeden kod olarak , bu da kodun yukarıdaki gibi bir alıntıyla anlamına geliyor. Bunu önlemenin en kısa yolu val()=
, bir çift parantez içinde her şeyi sarmak olacaktır , ancak daha sonra kod azaltılabilir val()=()
. Bulduğum ikinci en kısa yol kullanmaktır val()=hd[ ... ]
, yani her şeyi bir listeye sararız ve tür denetleyicisini mutlu etmek için ilk öğesini döndürürüz.
Veri dizesinin hiçbir parçasının fark edilmeden kaldırılamayacağından emin olmak için, val
-düşümlerdeki desen eşleşmesi tekrar işe yarar: Yazdırılacak son dizginin uzunluğu (ve böylece program uzunluğu) 195'e eşit olmalıdır, yazabilirizlet val t=... val 195=size t in print t end
fn
soyutlamanın bedenine bunun yerineprint(...)
. Dizenin bir parçasının çıkarılması, 189'dan daha az bir uzunluğa neden olur, böyleceBind
istisna atılır.
Hala bir sorun kaldı: bütün val 195=size t
kontrol basitçe bırakılabilir. Çeki bir grupta eşleşecek şekilde genişleterek bunu önleyebiliriz: val t=... val(216,u)=(n+size t,t)in print u end
böylece çek sonuçlarının ilişkisiz bir değişkende kaldırılmasıu
.
Toplamda, bu aşağıdaki 195 bayt çözeltisini verir:
val()=hd[(fn s=>let val t=s^"\""^String.toString s^"\")"val(195,u)=(size t,t)in print u end)"val()=hd[(fn s=>let val t=s^\"\\\"\"^String.toString s^\"\\\")\"val(195,u)=(size t,t)in print u end)"]
Operatör değişken adları gibi kullanmanın golf hile uygulamak !
, $
ve %
yerine n
,t
ve u
bazı beyaz yerden tasarruf için (bkz bu ipucunu son 182 bayt sürümüne yol).
Açıklamasında açıkça belirtilmeyen diğer tüm alt dize kaldırma işlemleri, sözdizimi veya tür hatasıyla sonuçlanmalıdır.
Düzenleme 1: length(explode t)
sadece size t
.
Edit 2: Farklı bir yaklaşım yaklaşımı ve bir "güvenlik açığı" olduğuna işaret eden Anders Kaseorg'a teşekkürler.