El değmemiş bir dünyayı sorgulamak


16

Bu meydan okuma Helka Homba'nın Bozulmamış Bir Dünyayı Programlama sorusuna dayanıyor . Bu sorudan, bozulmamış bir programın tanımı şöyledir:

Bozulmamış bir programı, herhangi bir hatası olmayan ancak N karakterlerin bitişik alt dizelerini kaldırarak değiştirirseniz hata verecek bir program olarak tanımlayalım 1 <= N < program length.

Örneğin, üç karakterli Python 2 programı

`8`

bozulmamış bir programdır ( teşekkürler, Sp ) çünkü uzunluk 1 alt dizelerinin kaldırılmasından kaynaklanan tüm programlar hatalara neden olur (sözdizimi hataları aslında, ancak her türlü hata yapacaktır):

8`
``
`8

ve ayrıca uzunluk 2 alt dizelerinin kaldırılmasından kaynaklanan tüm programlar hatalara neden olur:

`
`

Örneğin, `8hata yapmayan bir program `8`olsaydı, bozulmamış olmazdı, çünkü alt dize kaldırmanın tüm sonuçları hata vermelidir.

Notlar:

  • Derleyici uyarıları hata olarak sayılmaz.
  • Hata yapan alt programlar, nihayetinde olursa olsun hata aldıkları sürece girdi alabilir veya çıktı verebilir veya başka bir şey yapabilir.

Göreviniz, kendi kaynak kodunu tam olarak yazdıran, uygun bir quine ilişkin kuralları izleyen ve bozulmamış sıfır olmayan bir program oluşturmaktır .

Her dil için bayt cinsinden en kısa cevap kazanır.


Hata yapmayan dillerin rekabet edemeyeceğini mi sanıyorum?
ATaco

@ATaco Maalesef evet. Lisp gibi diğer diller sözdizimini faydalı bir bozulmamış program yapmak imkansız olacak şekilde yapılandırmıştır.
Shelvacu

RIP Aslında / Cidden
ATaco

'Her dil için bayt cinsinden en kısa cevap kazanır.' Bozulmamış bir program için en iyi önlemin kısa olduğundan emin değilim.
P. Siehr

@ P.Siehr Bunun yerine neyi önerirsiniz?
Shelvacu

Yanıtlar:


6

Haskell , 132 bayt

q x=if length x==132then putStr x else fail[];main=q$(++)<*>show$"q x=if length x==132then putStr x else fail[];main=q$(++)<*>show$"

Çevrimiçi deneyin!

Bu kinin bir uzantısıdır

main=putStr$(++)<*>show$"main=putStr$(++)<*>show$"

veri dizesini kendi alıntılanmış bir sürümüyle (kullanarak show) birleştirerek ve sonucu yazdırarak çalışır. Ancak, veri dizesindeki herhangi bir karakter başarısız olmadan kaldırılabileceği ve ayrıca $(++)<*>show$veya (++)<*>parça program kırılmadan bırakılabileceği için bu bozulmaz.

Bunu düzeltmek için q, belirli bir dizenin uzunluğunu kontrol eden ve fail132'den kısasa çağıran özel bir yazdırma işlevi tanımlanır. Bu, veri dizesinden herhangi bir dizinin kaldırılmasını ve ayrıca her iki durumda da sonuç olarak $(++)<*>show$veya (++)<*>geçirilen dize qdaha kısadır.

Gelen qsayısı 132kısaltılmış olabilir 1, 13, 32ya da 2, ancak her bir durumda tekrar faildenir.

Anlayabildiğim kadarıyla, diğer alt dizelerin kaldırılması sözdizimi veya tür hatasına neden olur, bu nedenle program ilk etapta bile derlenmez. (Haskell'in katı tip sistemi burada işe yarar.)

Düzenleme: Kusurları işaret ettikleri için Ørjan Johansen ve Shelvacu'ya teşekkürler!


Korkarım fail[]|length x/=122kaldırılabilir. fail[]:[putStr x|length x==122]daha iyi çalışabilir.
Ørjan Johansen

Argh, hayır, o |length x==122zaman çıkarılabilirdi. if length x==122 then putStr x else fail[]belki?
Ørjan Johansen

@ ØrjanJohansen İyi yakaladım, daha if then elseönce vardı ama kısaltabileceğimi düşündüm.
Laikoni

2
putStr xolabilir p xben öldürmeden önce ben çok uzun bir süre benim sistem ran üzerinde çalıştığımız hangi zaman, ben bu yüzden sonsuz döngü var, kuyruk çağrı özyineleme optimize edildi şüpheli. Nasıl düzeltileceğine dair herhangi bir öneri verecek kadar haskell bilmiyorum.
Shelvacu

@Shelvacu Whoops. Yeniden adlandırma piçin qonarmalısın.
Ørjan Johansen

4

Python 3 , 113 bayt

for[]in{113:[]}[open(1,"w").write((lambda s:s%s)('for[]in{113:[]}[open(1,"w").write((lambda s:s%%s)(%r))]:a'))]:a

Çevrimiçi deneyin!

Nasıl çalışır

İkincisi silinebildiğinden, birden çok ifadeyi kolayca kullanamayız, bu nedenle tek ifadeli bir alıntı ile başlayalım:

print((lambda s:s%s)('print((lambda s:s%%s)(%r))'))

Alt dize silmelerine karşı korumak için open(1,"w").writeyerine kullanıyoruz print. Python 3'te, dizenin hiçbir kısmının silinmediğinden emin olmak için writeyazacağımız karakter sayısını döndürür 113. Bunu, sözlükteki dönüş değerini arayarak {113:[]}ve sonuç üzerinde döngü yaparak for[]in…:a, boş bir yinelenebilir almazsak veya forifade silinirse başarısız olur .


1
Kodunuzun nasıl çalıştığına dair bir açıklama verebilir misiniz?
Shelvacu

@Shelvacu Evet, ekledi.
Anders Kaseorg

3

Ruby, 78 bayt

eval(*[($>.write((s=%{eval(*[($>.write((s=%%{%s})%%s)-78).chr])})%s)-78).chr])

Bunu mümkün olduğundan emin olmak için meydan okumayı düşündüğümde yazdım. Orijinal bozulmamış mücadeleye verdiğim yanıtlardan birinden aynı "sarmalayıcıyı" kullanıyor .

Açıklama:

  • eval(*[ İfade ])

    Bu , yakut program olarak hangi kodu döndürürse değerlendirir . Bu, kodun döndürdüğü dizenin geçerli bir ruby ​​programı olduğunu etkili bir şekilde test eder . Uygun olarak, yakut programlar boş olabilir veya yalnızca boşluktan oluşabilir.

    "Splat" işleci *, bir diziyi işleve bağımsız değişken olarak kullanmanızı sağlar. Bu ayrıca eval, kaldırılırsa, sonuçta ortaya çıkan programın (*[ ifade ]) edildiği anlamına gelir; bu, geçerli yakut değildir.

  • ($>.write( str )-78).chr

    $> STDOUT için kısa bir değişkendir.

    $>.write(foo) foo'yu STDOUT'a yazar ve daha da önemlisi bu kod için yazılan bayt sayısını döndürür.

    $>.write(foo)-78: Buraya 78 programın uzunluğu, bu yüzden program karıştırılmazsa, yazılan bayt sayısı da olacaktır. Bu nedenle, yönetilmeyen durumda, bu sıfır döndürür.

    num.chr num'u karakter olarak döndürür, örn. 0.chr , tek bir boş bayt içeren bir dize döndürür. Yönetilmeyen programda, bu, tek bir boş bayt içeren bir dize verecektir eval; bu, op olmayan geçerli bir yakut programıdır.

    Ayrıca, programın bir alt dizesi olabilir, öyle ki eval(*[(78).chr])veya eval(*[(8).chr])bu, sayısal sabitin herhangi bir sayı ile bitemeyeceği anlamına gelir (0, 4, 9, 10, 11, 12, 13, 26, 32, 35, 48 , 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 64, 95) çünkü bunlar geçerli tek karakterli yakut programları için ascii kodlarıdır.

  • %{ str }

    Bu, yakuttaki dize değişmez değerleri için daha az bilinen bir sözdizimidir. Burada kullanılmasının nedeni {}, dizede dengeli çiftlerin kullanılabilmesidir, bu da bu sözdiziminin kendisini içerebileceği anlamına gelir. Örneğin, %{foo{bar}}ile aynıdır "foo{bar}".

  • (s=%{ veri })%s

    Bu, sbu quine'nin verileri olan değişkeni printf dizesi olarak tanımlar .

    Ruby'deki atamalar atananları döndürür, bu nedenle bu ilk atama sve ardından çalıştırma ile aynıdırs%s

    %bir ipte yakut sprintf eşdeğeri için syntatic şekerdir. %sVeri içinde verinin kendisine gömülü olmalıdır gösterir.

    Bu kod biti, ayının veri bölümünü tanımlar ve tam kodu oluşturmak için kendi içine gömer.


3

Standart ML (MLton) , 204 182 189 bayt

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 varve funanahtar 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 , valSML'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 printiş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 printveya "Hey"bir Pattern and expression disagreehataya 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.toStringDize çı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 endfn 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 endbö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 ubazı 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.


"\""Doğrudan yazarak ve String.toStringkaçmak için kullanarak 2 bayt .
Anders Kaseorg

Bekle, bu korkunç: MLton "boş çıktı ( TIO ) üreten programı kabul ediyor gibi görünüyor .
Anders Kaseorg

@AndersKaseorg Huh, bu garip. Ancak bu sorunu başka bir sorunla gidermek mümkün olmalıdır let ... in ... end.
Laikoni

@AndersKaseorg Umarım yeni "güvenlik açıkları" getirmeden bu sorunu çözdüm.
Laikoni

Aslında "bir program olarak kabul eden MLton'a baktım ve hata bu taahhütte düzeltildi gibi görünüyor , bu yüzden belki de 182 veya 180'im MLton'un yayınlanmamış Git sürümünü belirttiğiniz sürece iyidir.
Anders Kaseorg
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.