";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
Tırnaksız sürüm: Kodlama alanında deneyin.
Alıntılanan sürüm: Kodlama alanında deneyin.
Çıktının böyle bir şeye benzediğini unutmayın
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
çünkü kod bildirimi bildirimle (her biri ;
bildirimi bitirir) yorumlanır ve her bildirimin değerini ve türünü gösterir.
Arka fon
SML'de formun bir örneği vardır <code>"<code in quotes>"
:
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
ve biri şu şekildedir "<code in quotes>"<code>
:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
Her ikisi de, <code>
-part'ın tırnak içermediğine güvenir ve bu nedenle herhangi bir şeyden kaçma ihtiyacı olmadan alıntılanabilir,"
çıktısı için gerekli str(chr 34)
.
Ayrıca, örtük tanımlayıcıya da büyük ölçüde güvenirler. it
, bir bildirimde açık bir tanımlayıcı verilmediğinde kullanılan .
İlk quine içeren dizeye str(chr 34);
bağlanır , bir argüman alarak anonim bir işlevi başlatır , sonra sonuçta oluşan dizeyi birleştirir ve yazdırır. Bu anonim işlev doğrudan program kodunu içeren bir dizeye uygulanır, böylece birleştirme sağlarit
"
fn x=>
x
x^it^x^it
x^it^x^it
<code>"<code>"
.
İkinci quine dizesi olarak sadece program kodu ile başlar ";str(chr 34)^it;print(it^it)";
bağlıdır it
. Daha sonra str(chr 34)^it;
bir dizginin başlangıcına bir teklif birleştirir ve yine açık bir tanımlayıcı verilmediği için, elde edilen dize "<code>
bağlanır it
. Sonunda print(it^it)
dizeyi "<code>"<code>
, daha sonra yazdırılan kendisi ile birleştirir .
açıklama
Düzenleme: Artık 108 baytlık sürümle güncel değil, ancak bu açıklamayı okuduktan sonra da anlayabilirsiniz.
Alıntı güvenli quine yukarıdaki yaklaşımların her ikisini de birleştirir ve formun kendisidir "<code>"<code>
. Bunu tekrar tırnak içine almak getirisi""<code>"<code>"
almak, böylece boş bir dize ve daha sonra diğer formun bir quine elde ederiz.
Bu, programın ya "<code>
tanımlayıcı tarafından kendi kaynağında verildiği it
ya it
da sadece "
ve bizim kaynağımızın <code>
argüman olarak verildiği ve bu nedenle böyle bir argümanı işleyen bir işlev olması gerektiği anlamına gelir.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
Hangi durumda olduğumuzu belirlemek için, boyutunun it
1'den büyük olup olmadığını kontrol ederiz . Değilse o zaman it
öyle "
ve ikinci durumdayız, bu nedenle else
-part fn x=>print(it^it^x^it^x^it)
, daha sonra çağrıldığı için anonim bir işlev döndürür; . Liderliğe dikkat edinit^it^
programın başında boş dize için gereklidir.
Eğer size it
içinde bulunduğumuz 1'den büyüktür then
-bölümüne ve sadece gerçekleştirmek print(it^it)
, hakkını? Tam olarak değil, çünkü size SML'nin güçlü bir şekilde yazıldığını söylemeyi ihmal ettim, bu da bir koşulun if <cond> then <exp_1> else <exp_2>
her zaman aynı türe sahip olması gerektiği anlamına gelir, bu da ifadelerin <exp_1>
ve <exp_2>
aynı tipte olması gerektiği anlamına gelir . Parçanın türünü zaten biliyoruz else
: Bir dize alan ve daha sonra çağrı yapan anonim bir fonksiyonun print
türü vardır string -> <return type of print>
ve print
türü vardır string -> unit
( unit
bir şekilde void
diğer dillerde benzer ), bu nedenle ortaya çıkan tür tekrar olur string -> unit
.
Yani then
parça sadece print(it^it)
türü olan unit
olsaydı, bir tür uyumsuzluğu hatası alırdık. Peki nasıl fn _=>print(it^it)
? ( _
Kendi başına Bu anonim fonksiyonu türünü etti kullanılmayan bir argüman için joker karakterdir) öylesine bir zorlar koşullu bağlamında, keyfi bir tipine karşılık gelmektedir bu işe yarar türü. (Type değişkeni type ile somutlaştırılır .) Ancak, bu durumda anonim işlev asla çağrılmadığından hiçbir şey basmazdık! Biz giderken Unutmayın genel kodudur -bölümüne nedenle, bu onun aramadı sonra hiçbir şey geliyor gibi bir işleve -part değerlendirir ama.'a -> unit
'a
string -> unit
'a
string
then
"<code>"<code>
<code>
Bunun yerine formu olan bir sequentialisation kullanmak için keyfi türleri ve türü olabilir bütün sequentialisation türünü sağlar. Değerleri bakış fonksiyonel açıdan etmek ifadeler yan etkileri olabilir bu yüzden sadece atılır, ancak SML da zorunlu yapıları destekler. Kısacası, -part olarak alırız , böylece önce yazdırırız ve sonra doğru tipe sahip işlevi döndürürüz .(<exp_1>; ...; <exp_n>)
<exp_1>
<exp_n-1>
<exp_n>
<exp_1>
<exp_n-1>
(print(it^it);print)
then
print