Her durma programını yazdır (paralel bir tercüman yaz)


26

Bu zorluğun amacı (sonunda) her olası durdurma programını seçtiğiniz bir dilde vermektir. İlk başta bu imkansız gelebilir, ancak bunu çok dikkatli bir şekilde yürütme emri seçimiyle yapabilirsiniz.

Aşağıda bunu göstermek için bir ASCII diyagramı bulunmaktadır. Sütunların mümkün olan her programın bir numarasını temsil etmesine izin verin (her program sonlu bir alfabedeki sınırlı sayıda semboldür). Her satır bu programın yürütülmesinde tekil bir adımı temsil edelim. Bir Xtemsilci, o zaman adımında bu program tarafından gerçekleştirilen yürütmeyi temsil eder.

 step#  p1 p2 p3 p4 p5 p6
     1  X  X  X  X  X  X
     2  X  X  X  X  X  
     3  X  X     X  X
     4  X  X     X  X
     5  X  X     X
     6     X     X
     7     X     X
     8     X     X
     9     X     X
     ∞     X     X

Anlatabileceğiniz gibi, programlar 2 ve 4 durmuyor. Bunları birer birer uygulayacak olsaydınız, kontrol cihazınız program 2 olan sonsuz döngüye takılır ve hiçbir zaman program 3 ve öteye çıkmaz.

Bunun yerine, bir kırlangıç yaklaşımı kullanın . Harfler ilk 26 adım için olası bir yürütme sırasını temsil ediyor. *Ler o program durdurdu ve çıktısı alınır yerlerdir. .Ler henüz infaz edilmemiş adımlardır.

 step#  p1 p2 p3 p4 p5 p6
     1  A  C  F  J  N  R  V
     2  B  E  I  M  Q  *  Z
     3  D  H  *  P  U
     4  G  L     T  Y
     5  K  O     X
     6  *  S     .
     7     W     .
     8     .     .
     9     .     .
     ∞     .     .

Hedef dil için gerekenler

Hedef dil (paralel olarak tercüme edilen) Turing-tamamlanmış olmalıdır. Bunun dışında , çok daha büyük dillerin tam Turing altkümeleri de dahil olmak üzere, Turing tamamlandı herhangi bir dil olabilir . Ayrıca döngüsel etiket sistemi kuralları gibi şeyleri yorumlamakta özgürsünüz. Bunun neden Turing-tamamlandı olduğunu gösterebildiğiniz sürece, test etmek için bir dil yaratmanıza izin verilir.

Örnek olarak, eğer beyin hasarı test etmeyi seçerseniz []-+<>, giriş desteklenmediği ve çıkış sadece atıldığı için sadece altkümeyi test etmek en iyisidir (aşağıya bakınız).

“Golf” kontrol programına gelince (ki golf oynuyorsunuz), özel bir gereklilik yoktur. Normal dil kısıtlamaları geçerlidir.

Sonsuz bir program listesi nasıl oluşturulur

Programlama dillerinin çoğu sonlu bir alfabeden gelen bir dizi sembol olarak gösterilebilir. Bu durumda, artan uzunluk sırasına göre her olası programın bir listesini numaralandırmak nispeten kolaydır. Kullandığınız alfabe , hedef dilin gereksinimlerini temsil etmelidir . Çoğu durumda, bu yazdırılabilir ASCII'dir. Diliniz Unicode'u ek bir özellik olarak destekliyorsa, mümkün olan her Unicode karakter kombinasyonunu test etmemelisiniz, sadece ASCII. Diliniz yalnızca kullanıyorsa []-+<>, "comment" ASCII karakterlerinin çeşitli kombinasyonlarını test etmeyin. APL gibi dillerin kendi özel harfleri olur.

Diliniz en iyi şekilde Fractran veya Turing Machines gibi alfabetik olmayan bir şekilde tanımlanıyorsa, olası tüm geçerli programların bir listesini oluşturmanın eşit derecede geçerli başka yöntemleri de vardır.

Sürekli büyüyen programların listesini yorumlama

Bu zorluğun kilit kısmı, büyüyen programların listesi için paralel bir tercüman yazmaktır. Bunun için bazı temel adımlar var:

  • Listeye sınırlı sayıda program ekleyin
  • Listedeki her programı belirli bir süre için ayrı ayrı yorumlayınız. Bu, her biri için bir talimat adımı gerçekleştirilerek gerçekleştirilebilir. Bütün ülkeleri kurtar.
  • Tüm sonlandırma / hata atma programlarını listeden kaldır
  • Temiz bir şekilde durmuş * programların çıktısını alın
  • Listeye daha fazla program ekleyin
  • Her programı sırayla benzetin, kaldığı yerden daha eski programların çalıştırılmasını sağlayın
  • Tüm sonlandırma / hata atma programlarını listeden kaldır
  • Temiz bir şekilde durmuş * programların çıktısını alın
  • tekrar et

* Yalnızca temiz bir şekilde durduran programları çıkarmalısınız. Bu, yürütme sırasında atılan sözdizimi hataları veya yakalanmayan istisnalar olmadığı anlamına gelir. Girdi isteyen programlar da çıktı alınmadan sonlandırılmalıdır. Bir program çıktı üretirse, onu sonlandırmamalısınız, sadece çıktıları atmalısınız.

Daha fazla kural

  • Test edilen programları içerecek şekilde yeni başlıklar oluşturmamalısınız, çünkü bu paralel işletim sistemini ana işletim sistemi işletim sistemine / diğer yazılıma yükler.
  • Düzenleme: Gelecekteki potansiyel boşlukları kapatmak için eval, test edilen programın kodunun bir kısmına (veya ilgili bir fonksiyona) izin verilmez . Sen can eval tercüman kodundan bir kod bloğu. (BF-in-Python cevabı bu kurallar uyarınca hala geçerlidir.)
  • Bu
  • İçinde Gönderiminizi yazma dili gelmez sen çıkışının / test ediyoruz dil olarak aynı olması gerekir.
  • Kullanılabilir hafızanızın sınırsız olduğunu varsaymalısınız.
  • Turing'in eksiksiz olduğunu kanıtlarken, girişin programa kodlanmış olduğunu ve çıkışın programın iç durumundan okunabileceğini varsayabilirsiniz.
  • Programın kendisi çıktı, muhtemelen yanlış veya çokgrup.

7
Nedenini anlamak çok uzun sürdü"If your program outputs itself, it is probably wrong or a polyglot."
trichoplax

1
Kullanılabilir hafızanın sınırsız olduğunu varsayabiliriz (bunun mümkün olduğunu sanmıyorum)
KSab

1
@KSab Evet ve kesinlikle başka türlü mümkün değil.
PhiNotPi

1
Takip zorluğu ( çok daha zor): Her durmayan programın çıktısını alın.
Milo Brandt

1
Aynı programı bir kereden fazla çıkarmak kabul edilebilir mi?

Yanıtlar:


9

Python'da subleq OISC, 317 269 ​​bayt

import collections
g=0
P={}
while 1:
    P[g]=[[0],collections.defaultdict(int,enumerate(list(int(x)for x in reversed(str(g)))))]
    g+=1
    for o,[a,p]in P.items():
        i=a[0]
        p[i+p[i+1]]-=p[i+p[i]]
        if p[i+p[i+1]]<=0:a[0]+=p[i+2]
        else:a[0]+=3
        if a[0]<0:print o;del P[o]

https://esolangs.org/wiki/Subleq

Bir subleq programı, genişletilebilir bir tamsayı listesi (p) ve bir komut göstericidir (i). Bu subleq değişkeni, wiki konuşma sayfasının sınırlanmış değerlerle tam bir bütünleşme için gerekli olduğunu öne sürdüğü göreceli adreslemeyi kullanır. Her onay, işlem p[i+p[i+1]]-=p[i+p[i]]gerçekleştirilir ve ardından i+=p[i+2]işlem sonucu <= 0 ise, aksi takdirde i+=3. Eğer negatifsem, program durur.

Bu uygulama, başlangıç ​​durumu 0 olan bir başlangıç ​​talimatı işaretçisiyle bir basamaklı negatif olmayan tam sayılardan (0-9) oluşan her programı test eder.

Output:
21 (which represents the program [1 2 0 0 0 0 0...]
121
161
221
271
351
352
461
462
571
572
681
682
791
792

Golf nedeniyle, çıktı tersine çevrilir. Yukarıdaki özellik tersten düzeltilebilir, ancak daha sonra uygulamada kullanılan kodla eşleşmeyecektir, bu yüzden onu bu şekilde tarif etmedim.

EDIT: Sınırlandırılmamış basit bir büyüme gösteren ilk program 14283'tür, ki bu da hafıza konumundaki 6 değerin değerini azaltır ve her üç kenenin bir sonraki negatif hücreye (her hücrede 0'ın aksine) açık bir 0 yazar.


9

CJam'da Bitsel Döngüsel Etiket , 98 87 84 77 bayt

L{Z):Z2b1>_,,1>\f{/([\:~]a2*}+{)~[\({1+(:X+\_0=Xa*+}{0+\1>}?_{]a+}{];p}?}%1}g

Bu sonsuz bir döngü olduğundan, çevrimiçi tercümanda bunu doğrudan test edemezsiniz. Ancak, burada oynamak için STDIN'den yineleme sayısını okuyan alternatif bir sürüm . Tüm programı test etmek için Java tercümanına ihtiyacınız olacak .

BCT, Döngüsel Etiket Sistemlerinin minimalist bir çeşididir . Bir program iki ikili dizi ile tanımlanır: a (döngüsel) komut listesi ve bir başlangıç ​​durumu. Programları yazdırırken hayatımı kolaylaştırmak için kendi notumu tanımladım: her bir dizge CJam tarzı bir tamsayı dizisi olarak verildi ve tüm program [[...]]örneğin

[[[0 0 1 1] [0 1 1 1 0]]]

Ayrıca boş başlangıç ​​durumlarına veya boş talimat listelerine de izin vermiyorum.

BCT'deki talimatlar şu şekilde yorumlanır:

  • Talimat buysa, 0öncü bit'i geçerli durumdan kaldırın.
  • Eğer talimat buysa, talimat 1listesinden başka bir bit oku, onu çağır X. Geçerli durumdan 1baştaki bit ise, geçerli duruma ekleyin X, aksi halde hiçbir şey yapmayın.

Mevcut durum hiç boşalırsa, program durur.

İlk birkaç durdurma programı

[[[0] [0]]]
[[[0] [1]]]
[[[0 0] [0]]]
[[[0] [0 0]]]
[[[0 0] [1]]]
[[[0] [0 1]]]
[[[0 1] [0]]]
[[[0] [1 0]]]
[[[0 1] [1]]]
[[[0] [1 1]]]

Daha fazlasını görmek istiyorsanız, yukarıda bağladığım çevrimiçi tercümandaki sürümü inceleyin.

açıklama

İşte kod nasıl çalışıyor. Kırlangıç ​​kuyruğunu takip etmek için her zaman tüm programları içeren yığında bir dizi olacaktır. Her program, programın [[0 1 0] [1 0]]mevcut durumunun yanı sıra program kodunun (örn. ) Dahili bir gösterimidir . Hesaplamayı yapmak için yalnızca ikincisini kullanacağız, ancak programı durduğunda yazdırmak için eskisini hatırlamamız gerekecek. Bu program listesi basit bir şekilde boş bir diziye başlatılır L.

Kodun geri kalanı, {...1}gönce bu listeye bir veya daha fazla program ekleyen ve her program için bir adım hesaplayan sonsuz bir döngüdür . Durdurulan programlar yazdırılır ve listeden çıkarılır.

Programları ikili sayıyı sayarak numaralandırıyorum. Önde gelen basamak, tüm programları öncü 0'larla da alabilmemiz için elimden edilmiştir. Bu tür kesilmiş her iki ikili gösterim için, talimatlar ve başlangıç ​​durumu arasındaki muhtemel her bölünme için bir programı zorluyorum. Örneğin, sayaç şu anda ise 42, ikili gösterimidir 101010. Önde gelenlerden boşalıyoruz 1ve boş olmayan bütün parçaları itiyoruz:

[[[0] [1 0 1 0]]]
[[[0 1] [0 1 0]]]
[[[0 1 0] [1 0]]]
[[[0 1 0 1] [0]]]

Boş talimatlar veya durumlar istemediğimiz için, sayacı 4 'te başlıyoruz [[[0] [0]]]. Bu numaralandırma aşağıdaki kodla yapılır:

Z):Z    e# Push Z (initially 3), increment, and store in Z.
2b1>    e# Convert to base 2, remove initial digit.
_,      e# Duplicate and get the number of bits N.
,1>     e# Turn into a range [1 .. N-1].
\       e# Swap the range and the bit list.
f{      e# Map this block onto the range, copying in the bit list on each iteration.
  /     e#   Split the bit list by the current value of the range.
  (     e#   Slice off the first segment from the split.
  [     
    \:~ e#   Swap with the other segments and flatten those.
  ]     e#   Collect both parts in an array.
  a2*   e#   Make an array that contains the program twice, as the initial state is the
        e#   same as the program itself.
}
+       e# Add all of these new programs to our list on the stack.

Kodun geri kalanı, BCT hesaplamasının bir adımını bu çiftlerin ikinci yarısında yapan ve durduğunda programı kaldıran program listesine bir blok eşler:

)~     e# Remove the second half of the pair and unwrap it.
[      e# We need this to wrap the instructions and current state back in an array
       e# again later.
\(     e# Bring the instruction list to the top and remove the leading bit.
{      e# If it's a 1...
  1+   e#   Append a 1 again (the instructions are cyclic).
  (:X+ e#   Remove the next bit, store it in X and also append it again.
  \_0= e#   Bring the current state to the top, get its first bit.
  Xa*+ e#   Append X if that bit was 1 or nothing otherwise.
}{     e# Else (if it's a 0...)
  0+   e#   Append a 0 again (the instructions are cyclic).
  \1>  e#   Discard the leading bit from the current state.
}?
_      e# Duplicate the current state.
{      e# If it's non-empty...
  ]a+  e#   Wrap instructions and state in an array and add them to the program
       e#   pair again.
}{     e# Else (if it's empty)...
  ];p  e# Discard the instructions and the current state and print the program.
}?

Güzel (+1). Bazı veri baytları, ilk veri dizisi olarak sadece 1 ile sınırlandırılmış olsalar bile BCT'nin Turing olduğu gerçeğini kullanarak kaydedilebilir (“durumunuz”). Örneğin, art arda pozitif her tam sayıyı ikili olarak 1P olarak yorumlayın, ardından P'yi 1'e uygulayın ve çıkış P iff yürütmesi sona erer (yine kırma). (Tabii ki, 0 ile başlayan herhangi bir P o zaman listede olacaktı, çünkü ilk veri dizisini derhal silecekti.)
res

8

Python'da Brainfuck, 567 bayt

Brainfuck'un tercüman yazmak için en zor dil olduğu için nispeten basit bir çözüm.

Brainfuck'ın bu uygulamasında veri işaretçisi 0'dan başlayarak sadece pozitif bir değer alabilmeye izin verdi (0'dan sola gitmeye çalışırsa bir hata olarak kabul edilir). Veri hücreleri 0 ila 255 arasındaki değerleri alabilir ve kaydırır. 5 geçerli talimat ><+[]( -sargı nedeniyle gerekli değildir).

Şimdi çıktıların doğru olduğunu düşünüyorum, ancak her türlü çözümü yazdırdığından emin olmak zor, bu yüzden bazılarını kaçırmış olabilirim.

o="><+]["
A="[]if b%s1<0else[(p,a+1,b%s1,t+[0],h)]"
C="[(p,h[a]+1,b,t,h)if t[b]%s0else(p,a+1,b,t,h)]"
I=lambda s,i:i*">"if""==s else o[o.find(s[0])+i-5]+I(s[1:],i*o.find(s[0])>3)
s="";l=[]
while 1:
 s=I(s,1)
 r=[];h={}
 for i in range(len(s)):
    if s[i]=="[":r+=[i]
    if s[i]=="]":
     if r==[]:break
     h[r[-1]]=i;h[i]=r[-1];r=r[:-1]
 else:
    if r==[]:
     l+=[(s,0,0,[0],h)];i=0
     while i<len(l):
        p,a,b,t,h=l[i]
        if a>=len(p):print p;l[i:i+1]=[]
        else:l[i:i+1]=eval([A%("+","+"),A%("-","-"),"[(p,a+1,b,t[:b]+[(t[b]+1)%256]+t[b+1:],h)]",C%">",C%"=="][o.find(p[a])]);i+=1

İlk birkaç çıkış:

>
+
>>
+>
><
>+
++
[]
>>>
+>>

Ve ilk 2000’in bir listesi: http://pastebin.com/KQG8PVJn

Ve nihayet []onlarla ilk 2000 çıktısının bir listesi : http://pastebin.com/iHWwJprs
(geri kalan her şey geçerli oldukları sürece önemsizdir)

Daha uzun süren programlar daha sonra basılacağından, çıktının sıralı bir sırada olmadığını unutmayın, ancak çoğu için bu şekilde görünebilir.


1
Hem çıplak [-]hem [+]de kesinlikle görünmesi gerekir çünkü döngünün içeriği kolayca atlanır (sarma yoktur).
PhiNotPi

@ SP3000 [-]ve [+]şimdi sabit gereken bir hata oldu ve ayarlarla güncelledik
KSab

1
Neden destekliyoruz .? Turing-complete BF alt kümesi için gerekli değildir ve çıktı yine de göz ardı edilmelidir. Ayrıca, hücre değerlerini etrafa sardığına göre, yalnızca birine -ve ihtiyacına ihtiyacın olduğunu düşünüyorum +.
Martin Ender,

@ MartinBüttner Soruyu yanlış anlamış gibiyim; 'Turing complete subset' bölümünü okumadım. Ancak bu, (çoğu) dilde mücadeleyi neredeyse eşdeğer yapmaz mı? Brainfuck ile (veya belki de daha basit bir şey) 1'e 1 yenisini yapamadıysanız, örneğin buradaki c kodu: en.wikipedia.org/wiki/Brainfuck#Commands .
KSab,

2
Stackoverflow.com/questions/1053931/… ' a ve özellikle OISC girişine bakın. Ayrıca CA Kural 110 ve Döngüsel Etiket Sistemlerine bakın. Bu mücadelede yaratıcı bir turing tam bir "dil" seçmek için çok fazla yer var.
Sparr

5

Python'da eğik çizgiler, 640 498 bayt

g=2
P={}
while 1:
    b=bin(g)[3:]
    P[b]=[[0],['',''],[b]]
    g+=1
    for d,[a,b,c]in P.items():
        s=c[0]
        if a[0]:
            if s.count(b[0]):s=s.replace(b[0],b[1],1)
            else:a[0]=0
        else:
            if s[0]=='0':
                if len(s)==1:del P[d];continue
                s=s[2:]
            else:
                b[0]=b[1]=''
                a[0]=1
                t=p=0
                while t<2:
                    p+=1
                    if p>=len(s):break
                    if s[p]=='0':
                        if p+1>=len(s):break
                        b[t]+=s[p+1]
                        p+=1
                    else:t+=1
                if t<2:del P[d];continue
        c[0]=s
        if len(s)==0:print d;del P[d]

https://esolangs.org/wiki////

Bir eğik çizgi programı bir dizedir, bu tercümanda '/' ve '\' karakterleriyle sınırlıdır. Bu uygulamada, / '1' ve \ '0'dır, python bin (x)' in kullanımıyla bazı golf oynamaya izin verir. Tercüman bir \ ile karşılaştığında, bir sonraki karakter çıkar ve her iki karakter de kaldırılır. Bir / ile karşılaştığında, aramayı arar ve / arama / değiştirme / kalıplar içindeki çıkış karakterleri içeren kalıpları değiştirir (\\ temsil \ ve \ / represent /). Bu değiştirme işlemi daha sonra arama dizesi artık mevcut olmayana dek dizede tekrar tekrar gerçekleştirilir, ardından yorumlama baştan başlar. Program boş olduğunda durur. Kapatılmamış bir dizi / desen veya daha sonra karaktersiz bir \ varsa bir program öldürülecektir.

Example output and explanations:
01 outputs '1' and halts
00 outputs '0' and halts
0101 outputs '11' and halts
0100 ...
0001
0000
010101
010100
010001
010000 ...
101110 replaces '1' with '', leaving '00', which outputs '0' and halts

4

Java'daki Ağaç Avcısı , 1.299 1.257 1.251 1.207 1.203 1.201 1.193 1.189 bayt

import java.util.*;class I{static class N{N l,r;byte v;}static class T extends Stack<N>{{push(new N());}void p(){pop();if(size()==0)p();}int i,h;char[]s;}static void s(T t){if(t.i>=t.s.length){t.h=1;return ;}char c=t.s[t.i];if(c=='<'){if(t.peek().l==null)t.peek().l=new N();t.push(t.peek().l);}if(c=='>'){if(t.peek().r==null)t.peek().r=new N();t.push(t.peek().r);}if(c=='^')t.p();if(c=='+')t.peek().v++;if(c=='-')t.peek().v--;if(c=='['&&t.peek().v==0){int i=1;while(i>0){t.i++;if(t.s[t.i]==']')i--;if(t.s[t.i]=='[')i++;}return;}if(c==']'&&t.peek().v!=0){int i=1;while(i>0){t.i--;if(t.s[t.i]==']')i++;if(t.s[t.i]=='[')i--;}return;}t.i++;}static char[]n(char[]a){String b="<^>[+-]";int q=a.length;for(int i=q-1;i>=0;i--){int j=b.indexOf(a[i]);if(j<6){a[i]=b.charAt(j+1);return a;}a[i]='<';}a=Arrays.copyOf(a,q+1);a[q]='<';return a;}public static void main(String[]a){List<T>z=new ArrayList<T>();char[]c={};while(true){T t=new T();t.s=c;if(b(c))z.add(t);c=n(c.clone());for(T u:z)try{s(u);if(u.h>0){z.remove(u);System.out.println(u.s);break;}}catch(Exception e){z.remove(u);break ;}}}static boolean b(char[]c){int i=0;for(char d:c){if(d=='[')i++;if(d==']')i--;if(i<0)return 0>0;}return i==0;}}

4

BrachylogYazışma sorunu , 10 bayt

≜;?{~c}ᵐ\d

Çevrimiçi deneyin!

Brüt zorlama çözümlerinin sonunda durduğu tüm olası yazışma sonrası sorunları üreten bir jeneratör olan işlev. (Yazışma sonrası problemin kaba uygulama çözümlerinin Turing-complete işlemi olduğu bilinmektedir.) TIO bağlantısı, bir jeneratörü tam bir programa dönüştüren ve her çıktıyı hemen üretildiği gibi basan bir başlık içerir (böylece, TIO öldürdüğünde) Program 60 saniyeden fazla yürütme süresi tüketdiğinden dolayı, şimdiye kadar üretilen çıktı görülebilir).

Bu, dizgilerin rakam dizeleri olarak verildiği, 0kendisinin dışında baştaki sıfırlara izin verilmediği , baştaki sıfırları içeren problemin çözümlerinin kabul edilmediği ve bir basamak dizisinin sayı olarak gösterilebileceği problemin bir formülasyonunu kullanır. , veya sayı eksi. Açıkçası, bunların hiçbiri dilin Turing'in bütünlüğü üzerinde herhangi bir etkisi yoktur (çünkü Post yazışma probleminin sıfır rakamını kullanmasına gerek yoktur).

Bu program sorunlara olası tüm çözümleri üreterek çalışır, daha sonra kendileri tarafından çözülen orijinal programları bulmak için geriye doğru çalışır. Bu nedenle, bireysel bir program birçok kez çıkarılabilir. Bunun cevabı geçersiz kılıp kestiği belli değil; Tüm durdurma programlarının sonunda en az bir kez (aslında, çok sayıda çözümü olan herhangi bir programın sonsuz sayıda çözümü olduğu gibi) sonsuz sayıda kez çıkacağını ve durmaksızın olmayan programların asla çıkmayacağını unutmayın.

açıklama

≜;?{~c}ᵐ\d
≜           Brute-force all numbers:
 ;?           Pair {the number} with {itself}
   {  }ᵐ      For each pair element:
    ~c          Brute-force a partition of that element into substrings
        \     such that the two elements each have the same number of substrings
        \     and group together corresponding substrings
         d    and remove duplicated pairs {to produce a possible output}

2

662, Seylan'da "Giriş / Çıkış Yapmadan Mor", 662

import ceylon.language{l=variable,I=Integer,m=map,S=String}class M(S d){l value t=m{*d*.hash.indexed};l I a=0;l I b=0;l I i=0;I g(I j)=>t[j]else 0;value f=m{97->{a},98->{b},65->{g(a)},66->{g(b)},105->{i},49->{1}};value s=m{97->((I v)=>a=v),98->((I v)=>b=v),65->((I v)=>t=m{a->v,*t}),66->((I v)=>t=m{b->v,*t}),105->((I v)=>i=v)};I&I(I)x{throw Exception(d);}I h(I v)=>f[v]?.first else x;shared void p(){(s[g(i)]else x)(h(g(i+1))-h(g(i+2)));i+=3;}}shared void run(){value a='!'..'~';{S*}s=expand(loop<{S*}>{""}((g)=>{for(c in a)for(p in g)p+"``c``"}));l{M*}r={};for(p in s){r=[M(p),*r];for(e in r){try{e.p();}catch(x){print(x.message);r=r.filter(not(e.equals));}}}}

Mor , burada yorumlaması istenen kendi kendini değiştiren bir tek dildir . Giriş ve çıkış bu görev için ilgili değildir, ben kaldırıldı o(potansiyel olarak) geçerli semboller öyle ki, tercüman, sembolün anlamını sadece a, b, A,B , ive 1(yazma için sadece okumak için sonuncusu değil).

Fakat Purple kendi kendini değiştirebildiğinden (ve kaynak kodunu veri olarak kullandığından), potansiyel olarak bu karakterlerden başka programlar da kullanışlıdır. koddaki tüm yazdırılabilir (boşluk olmayan) ASCII karakterlerine izin vermeyi (diğerleri olabilir) de yararlı, ancak kolay basılabilir değildir).

(Tercümanı bunun yerine izin verilen karakter dizisini komut satırı argümanı olarak alacak şekilde değiştirebilirsiniz - aaşağıda belirtilen açıklama satırını değiştirin . Sonra uzunluk 686 bayt olur.)

Bu yüzden "paralel" tercümanım bu karakterlerden (sonlu uzunluk ve sözlükbilim sırasına göre) tüm sonlu dizeleri yaratıyor ve her birini deniyor.

Yürütme için kasetten okunacak komut geçerli olmadığında, Purple hatasız olarak durur - bu nedenle geçersiz program yoktur ve çok sayıda durdurucu program vardır. (İlk adımda bile çoğu durduğunda, sadece 3 uzunluğundaki programların bazıları ikinci aşamaya gelir (ve daha sonra durur), ilk durmayanların uzunluğu 6'dır.

Tercümanım tarafından denenen sıradaki ilk hiç durmayan programın aaaiaa, ilk adımda akaydı 0'a (zaten olduğu) ve ikinci ve her adımın da imleci 0'a getirdiğini düşünüyorum. iaatekrar çalıştırılmasına neden oluyor .

"Standart" Mor tercümanım için yazılan kodun bir kısmını yeniden kullandım , ancak girdi ve çıktının kaldırılması nedeniyle, paralel tercümanım aynı anda birden fazla program yürütmek için ek mantığı da içerecek şekilde ondan biraz daha kısalıyor.

Yorum ve formatlanmış bir sürüm:

// Find (enumerate) all halting programs in (a non-I/O subset of) Purple.
//
// Question:  https://codegolf.stackexchange.com/q/51273/2338
// My answer: https://codegolf.stackexchange.com/a/65820/2338

// We use a turing-complete subset of the Purple language,
// with input and output (i.e. the `o` command) removed.

import ceylon.language {
    l=variable,
    I=Integer,
    m=map,
    S=String
}

// an interpreting machine.
class M(S d) {
    // The memory tape, as a Map<Integer, Integer>.
    // We can't modify the map itself, but we
    // can replace it by a new map when update is needed.
    l value t = m {
        // It is initialized with the code converted to Integers.
        // We use `.hash` instead of `.integer` because it is shorter.
        *d*.hash.indexed
    };

    // three registers
    l I a = 0;
    l I b = 0;
    l I i = 0;

    // get value from memory
    I g(I j) =>
            t[j] else 0;

    // Map of "functions" for fetching values.
    // We wrap the values in iterable constructors for lazy evaluation
    //  – this is shorter than using (() => ...).
    // The keys are the (Unicode/ASCII) code points of the mapped
    // source code characters.
    value f = m {
        // a
        97 -> { a },
        // b
        98 -> { b },
        // A
        65 -> { g(a) },
        // B
        66 -> { g(b) },
        // i
        105 -> { i },
        // 1
        49 -> { 1 }
    };

    // Map of functions for "storing" results.
    // The values are void functions taking an Integer,
    // the keys are the ASCII/Unicode code points of the corresponding
    // source code characters.
    value s = m {
        // a
        97 -> ((I v) => a = v),
        // b
        98 -> ((I v) => b = v),
        // Modification of the memory works by replacing the map with
        // a new one.
        // This is certainly not runtime-efficient, but shorter than
        // importing ceylon.collections.HashMap.
        // A
        65 -> ((I v) => t = m { a->v, *t }),
        // B
        66 -> ((I v) => t = m { b->v, *t }),
        // i
        105 -> ((I v) => i = v)
    };


    // Exit the interpretation, throwing an exception with the machine's
    // source code as the message.  The return type is effectively `Nothing`,
    // but shorter (and fits the usages).
    I&I(I) x {
        throw Exception(d);
    }

    // accessor function for the f map
    I h(I v) =>
            f[v]?.first else x;

    // a single step
    shared void p() {
        (s[g(i)] else x)(h(g(i + 1)) - h(g(i + 2)));
        i += 3;
    }
}

// the main entry point
shared void run() {
    // the alphabet of "Purple without I/O".
    value a = '!'..'~';
    //// possible alternative to use a command line argument:
    // value a = process.arguments[0] else '!'..'~';

    // an iterable consisting of all programs in length + lexicographic order
    {S*} s =
            // `expand` creates a single iterable (of strings, in this case)
            // from an iterable of iterables (of strings).
             expand(
        // `loop` creates an iterable by applying the given function
        // on the previous item, repeatedly.
        // So here we start with the iterable of length-zero strings,
        // and in each iteration create an iterable of length `n+1` strings
        // by concatenating the length `n` strings with the alphabet members.
        loop<{S*}>{ "" }((g) =>
                {
                    for (c in a)
                        for (p in g)
                            p + "``c``"
                }));

    // This is a (variable) iterable of currently running machines.
    // Initially empty.
    l {M*} r = {};

    // iterate over all programs ...
    for(p in s) {
        // Create a machine with program `p`, include it
        //  in the list of running machines.
        //
        // We use a sequence constructor here instead of
        //  an iterable one (i.e. `r = {M(p, *r)}` to prevent
        // a stack overflow when accessing the deeply nested
        // lazy iterable.
        r = [M(p), *r];
        // iterate over all running machines ...
        for(e in r) {
            try {
                // run a step in machine e.
                e.p();
            } catch(x) {
                // exception means the machine halted.
                // print the program
                print(x.message);
                // remove the machine from the list for further execution
                r = r.filter(not(e.equals));
            }
        }
        // print(r.last);
    }
}

2

SK combinator hesabı içinde Haskell , 249 bayt

data C=H|S|K|C:$C deriving(Eq,Show)
n(a:$b)=m a*n b
n a=m a
m S=1
m K=1
m(S:$a)=n a
m _=0
f H=[S,K,S:$H,K:$H,S:$H:$H]
f a=[S:$b:$c:$d|b:$d:$(c:$e)<-[a],d==e,n b*n c*n d>0]++[K:$a:$H|n a>0]++do b:$c<-[a];[d:$c|d<-f b]++[b:$d|n b>0,d<-f c]
l=H:(f=<<l)

Çevrimiçi deneyin!

Nasıl çalışır

SK birleştirici hesabı için arama-değer değerlendirme kuralları aşağıdaki gibidir:

(a) normal formda x , y , z için S xyzxz ( yz ) ; (b) K xyx , için x , y , normal şeklinde; (c) xyxy , eğer xx ′; (d) xyxy 'için x normal formda, eğer Yy' .


Sadece davranışları durdurmakla ilgilendiğimiz için, dili normal formda olmayan ancak tüm normal formların “değerlendirdiği” bir H sembolü ekleyerek dili biraz genişletiriz:

(a) normal formda x , y , z için S xyzxz ( yz ) ; (b ′) K x H ↦ x , x normal formda; (c) xyxy , eğer xx ′; (d) xyxy 'için x normal formda, eğer YY' ; (e) S = H; (f) K ↦ H; (g) SH ↦ H; (h) KH-H; (i) SHH ↦ H.







Herhangi bir uygulama H dikkate x sonsuz bir döngü sanki tedavi edilecek bir çalıştırma hatası olması ve hiçbir H tarafından üretildiği değerlendirmeler (e) sipariş - olacaktır burada bir bağlamda dışında: (i) yoksayılmış (üst seviye, herhangi bir K x ☐, herhangi bir göz ardı edilen K☐, x için normal biçimde x yok sayılan S x ☐ , herhangi bir göz ardı edilmiş S☐H). Bu şekilde, H eksikliği olan normal terimlerin durma davranışını etkilemiyoruz.

Bu değiştirilmiş kuralların faydaları, her normalleştirilebilir terimin H'ye özgü bir değerlendirme yoluna sahip olması ve her terimin under altında sınırlı sayıda olası ön-resme sahip olmasıdır. Dolayısıyla, kırlangıç ​​yaklaşımı kullanmak yerine, H'den tüm ters değerlendirme yollarının geniş kapsamlı ilk aramalarını daha verimli yapabiliriz.

nBir terimin normal formda olup olmadığını kontrol eder f, bir terimin olası tüm görsellerini bulur ve lH'den genişlik birinci arama tarafından üretilen tembel ve sınırsız bir normal listedir.

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.