Keluarkan setiap program penghentian (tulis juru bahasa paralel)

26

Tujuan dari tantangan ini adalah (pada akhirnya) mengeluarkan setiap program penghentian yang mungkin dalam bahasa pilihan Anda. Pada awalnya ini mungkin terdengar mustahil, tetapi Anda dapat melakukannya dengan pilihan perintah eksekusi yang sangat hati-hati.

Di bawah ini adalah diagram ASCII untuk menggambarkan hal ini. Biarkan kolom mewakili penomoran dari setiap program yang mungkin (setiap program adalah jumlah simbol hingga dari alfabet terbatas). Biarkan setiap baris mewakili langkah tunggal dalam pelaksanaan program itu. Sebuah Xmewakili eksekusi yang dilakukan oleh program itu pada langkah-waktu itu.

 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

Seperti yang Anda tahu, program 2 dan 4 tidak berhenti. Jika Anda menjalankannya satu per satu, controller Anda akan terjebak dalam infinite loop yaitu program 2 dan tidak pernah menghasilkan program 3 dan seterusnya.

Sebagai gantinya, Anda menggunakan pendekatan dovetailing . Surat-surat tersebut mewakili kemungkinan urutan eksekusi untuk 26 langkah pertama. Ini *adalah tempat di mana program itu terhenti dan dikeluarkan. Ini .adalah langkah-langkah yang belum dijalankan.

 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     .     .
     ∞     .     .

Persyaratan untuk bahasa target

Bahasa target (yang ditafsirkan paralel) harus Turing-complete. Selain itu, itu bisa bahasa apa pun yang Turing-lengkap, termasuk himpunan bagian Turing dari bahasa yang jauh lebih besar. Anda juga bebas menafsirkan hal-hal seperti aturan sistem tag siklik. Anda juga diizinkan membuat bahasa untuk diuji, selama Anda dapat menunjukkan mengapa bahasa Turing-lengkap.

Sebagai contoh, jika Anda memilih untuk menguji brainfuck, maka yang terbaik adalah hanya menguji []-+<>subset, karena input tidak didukung dan output dibuang begitu saja (lihat di bawah).

Ketika datang ke program "controller" (yang Anda main golf), tidak ada persyaratan khusus. Pembatasan bahasa normal berlaku.

Cara membuat daftar program tanpa batas

Mayoritas bahasa pemrograman dapat direpresentasikan sebagai serangkaian simbol dari alfabet hingga. Dalam hal ini, relatif mudah untuk menyebutkan daftar setiap program yang mungkin dalam urutan bertambah panjang. Alfabet yang Anda gunakan harus mewakili persyaratan bahasa target. Dalam kebanyakan kasus, ini adalah ASCII yang dapat dicetak. Jika bahasa Anda mendukung Unicode sebagai fitur tambahan, Anda tidak boleh menguji setiap kemungkinan kombinasi karakter Unicode, cukup ASCII. Jika bahasa Anda hanya menggunakan []-+<>maka jangan menguji berbagai kombinasi karakter "komentar" ASCII. Bahasa seperti APL akan memiliki huruf khusus mereka sendiri.

Jika bahasa Anda dijelaskan dengan cara non-alfabet, seperti Fractran atau Turing Machines, maka ada metode lain yang sama-sama valid untuk membuat daftar semua program yang mungkin valid.

Menafsirkan daftar program yang terus berkembang

Bagian penting dari tantangan ini adalah menulis penerjemah paralel untuk daftar program yang terus bertambah. Ada beberapa langkah dasar untuk ini:

  • Tambahkan sejumlah program ke dalam daftar
  • Menafsirkan setiap program dalam daftar secara individual untuk periode waktu yang terbatas. Ini dapat dicapai dengan melakukan satu langkah instruksi untuk masing-masing. Simpan semua status.
  • Hapus semua program terminating / melempar kesalahan dari daftar
  • Keluarkan program * yang terhenti dengan bersih
  • Tambahkan beberapa program lagi ke daftar
  • Simulasikan setiap program secara bergantian, ambil eksekusi dari program yang lebih lama di mana ia tinggalkan
  • Hapus semua program terminating / melempar kesalahan dari daftar
  • Keluarkan program * yang terhenti dengan bersih
  • ulangi

* Anda seharusnya hanya mengeluarkan program yang berhenti dengan bersih. Ini berarti bahwa tidak ada kesalahan sintaksis atau pengecualian yang tidak tertangkap selama eksekusi. Program yang meminta input juga harus dihentikan tanpa mengeluarkannya. Jika suatu program menghasilkan keluaran, Anda tidak harus menghentikannya, buang saja hasilnya.

Lebih banyak aturan

  • Anda tidak boleh menelurkan utas baru untuk memuat program yang telah diuji, karena ini melepaskan kerja paralelisasi ke OS host / perangkat lunak lain.
  • Sunting: Untuk menutup celah potensial di masa depan, Anda tidak diizinkan untuk eval(atau fungsi terkait lainnya) menjadi bagian dari kode program yang diuji . Anda dapat eval membuka kunci kode dari kode juru bahasa. (Jawaban BF-in-Python masih valid berdasarkan aturan ini.)
  • Ini adalah
  • Bahasa tempat Anda menulis kiriman tidak harus sama dengan bahasa yang Anda uji / hasilkan.
  • Anda harus mengasumsikan bahwa memori yang tersedia tidak terikat.
  • Saat membuktikan kelengkapan Turing, Anda dapat mengasumsikan bahwa input di-hardcode ke dalam program, dan hasilnya dapat dibaca dari kondisi internal program.
  • Jika program Anda menghasilkan sendiri, itu mungkin salah atau polyglot.
PhiNotPi
sumber
7
Butuh waktu terlalu lama bagi saya untuk menyadari mengapa"If your program outputs itself, it is probably wrong or a polyglot."
trichoplax
1
Bolehkah kita berasumsi bahwa memori yang tersedia tidak terikat (saya rasa ini tidak mungkin dilakukan)
KSab
1
@ Ya, dan itu pasti tidak mungkin terjadi.
PhiNotPi
1
Tantangan tindak lanjut ( jauh lebih sulit): Keluarkan setiap program yang tidak berhenti.
Milo Brandt
1
Apakah dapat menerima program yang sama lebih dari satu kali?

Jawaban:

9

subleq OISC dengan Python, 317 269 ​​byte

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

Program subleq adalah daftar bilangan bulat yang dapat diperluas (p) dan penunjuk instruksi (i). Varian subleq ini menggunakan pengalamatan relatif, yang disarankan oleh halaman pembicaraan wiki untuk memastikan kelengkapan dengan nilai yang dibatasi. Setiap centang, operasi p[i+p[i+1]]-=p[i+p[i]]dilakukan, dan kemudian i+=p[i+2]jika hasil operasi adalah <= 0, jika tidak i+=3. Jika saya pernah negatif, program berhenti.

Implementasi ini menguji setiap program yang status awalnya terdiri dari bilangan bulat non-negatif satu digit (0-9) dengan penunjuk instruksi awal 0.

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

Outputnya terbalik, karena alasan golf. Spesifikasi di atas dapat disajikan kembali secara terbalik, tetapi kemudian tidak akan cocok dengan kode yang digunakan dalam implementasi, jadi saya tidak menggambarkannya seperti itu.

EDIT: Program pertama yang menunjukkan pertumbuhan tanpa batas sederhana adalah 14283, yang menurunkan nilai pada lokasi memori 6 dan menulis 0 secara eksplisit (sebagai lawan dari 0 implisit dalam setiap sel) ke sel negatif berikutnya, setiap tiga kutu.

Sparr
sumber
9

Tag Bitwise Cyclic dalam CJam, 98 87 84 77 byte

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

Karena ini adalah infinite loop, Anda tidak dapat langsung menguji ini dalam juru bahasa online. Namun, berikut ini adalah versi alternatif yang membaca jumlah iterasi dari STDIN untuk Anda mainkan. Untuk menguji program lengkapnya, Anda memerlukan penerjemah Java .

BCT adalah varian minimalis dari Cyclic Tag Systems . Suatu program didefinisikan oleh dua string biner: daftar instruksi (cyclic) dan status awal. Untuk membuat hidup saya lebih mudah saat mencetak program, saya telah menetapkan notasi saya sendiri: masing-masing string diberikan sebagai array integer gaya CJam, dan seluruh program dikelilingi [[...]], misalnya

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

Saya juga tidak mengizinkan status awal kosong atau daftar instruksi kosong.

Instruksi dalam BCT ditafsirkan sebagai berikut:

  • Jika instruksi tersebut 0, hapus bit terkemuka dari keadaan saat ini.
  • Jika instruksinya 1, baca bit lain dari daftar instruksi, panggil itu X. Jika bit terkemuka dari kondisi saat ini adalah 1, tambahkan Xke kondisi saat ini, jika tidak lakukan apa-apa.

Jika keadaan saat ini menjadi kosong, program terhenti.

Beberapa program penghentian pertama adalah

[[[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]]]

Jika Anda ingin melihat lebih banyak, lihat versi di penerjemah online yang saya tautkan di atas.

Penjelasan

Berikut adalah cara kerjanya. Untuk melacak dovetailing kami akan selalu memiliki array pada stack yang berisi semua program. Setiap program adalah pasangan representasi internal dari kode program (seperti [[0 1 0] [1 0]]) serta keadaan program saat ini. Kami hanya akan menggunakan yang terakhir untuk melakukan perhitungan, tetapi kami harus mengingat yang pertama untuk mencetak program setelah terhenti. Daftar program ini hanya diinisialisasi ke array kosong dengan L.

Sisa kode adalah loop tak terbatas {...1}gyang pertama kali menambahkan satu atau lebih program ke daftar ini dan menghitung satu langkah pada setiap program. Program yang berhenti dicetak dan dihapus dari daftar.

Saya menghitung program dengan menghitung angka biner. Digit terkemuka dibuka untuk memastikan bahwa kita bisa mendapatkan semua program dengan 0s juga. Untuk setiap representasi biner terpotong seperti itu, saya mendorong satu program untuk setiap kemungkinan pemisahan antara instruksi dan keadaan awal. Misalnya jika penghitung saat ini di 42, representasi binernya adalah 101010. Kami menyingkirkan yang terdepan 1dan mendorong semua benda yang tidak kosong:

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

Karena kami tidak ingin instruksi atau status kosong, kami memulai penghitung di 4, yang memberi [[[0] [0]]]. Penghitungan ini dilakukan dengan kode berikut:

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.

Sisa kode memetakan blok ke daftar program, yang melakukan satu langkah perhitungan BCT pada bagian kedua dari pasangan ini dan menghapus program jika terhenti:

)~     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.
}?
Martin Ender
sumber
Bagus (+1). Beberapa byte mungkin disimpan menggunakan fakta bahwa BCT Turing lengkap bahkan jika dibatasi hanya menggunakan 1 sebagai datastring awal ("negara" Anda). Misalnya, tafsirkan setiap bilangan bulat positif berturut-turut dalam biner sebagai 1P, kemudian jalankan P pada 1 dan output P jika eksekusi berakhir (dovetailing lagi). (Tentu saja, setiap P yang dimulai dengan 0 akan ada di daftar, karena itu akan segera menghapus data awal.)
res
8

Brainfuck dengan Python, 567 byte

Solusi yang relatif sederhana, karena Brainfuck bukanlah bahasa yang paling sulit untuk dituliskan seorang penerjemah.

Implementasi Brainfuck ini memiliki penunjuk data mulai dari 0, hanya diizinkan untuk mengambil nilai positif (dianggap sebagai kesalahan jika mencoba untuk pergi ke kiri 0). Sel-sel data dapat mengambil nilai dari 0 hingga 255 dan membungkus. 5 instruksi yang valid adalah ><+[]( -tidak perlu karena pembungkusnya).

Saya pikir hasilnya sudah benar sekarang, tetapi sulit untuk memastikan bahwa itu mencetak setiap solusi yang mungkin jadi saya mungkin kehilangan beberapa.

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

Beberapa ouputs pertama:

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

Dan daftar 2000 pertama: http://pastebin.com/KQG8PVJn

Dan akhirnya daftar 2000 output pertama dengan []mereka: http://pastebin.com/iHWwJprs
(semua sisanya sepele selama mereka valid)

Perhatikan bahwa output tidak dalam urutan, meskipun mungkin terlihat seperti itu bagi banyak dari mereka, karena program yang membutuhkan waktu lebih lama akan dicetak nanti.

KSab
sumber
1
Baik yang telanjang [-]dan [+]pasti akan muncul karena isi dari loop hanya dilewati (tidak ada pembungkus yang terlibat).
PhiNotPi
@ Sp3000 [-]dan [+]merupakan bug yang sekarang harus diperbaiki dan saya telah memperbarui dengan pengaturan
KSab
1
Mengapa Anda mendukung .? Ini tidak perlu untuk subset Turing-complete dari BF dan output harus diabaikan. Juga, karena Anda membungkus nilai sel sekitar, saya pikir Anda hanya perlu satu -dan +.
Martin Ender
@ MartinBüttner Sepertinya saya salah paham tentang pertanyaan; Saya tidak membaca bagian 'turing subset lengkap'. Namun bukankah ini membuat tantangan hampir setara dengan sebagian besar bahasa? Tidak bisakah Anda membuat pengganti 1 ke 1 dengan Brainfuck (atau mungkin sesuatu yang lebih sederhana), misalnya kode c di sini: en.wikipedia.org/wiki/Brainfuck#Commands .
KSab
2
Lihatlah stackoverflow.com/questions/1053931/... khususnya entri OISC. Juga, lihat CA Rule 110 dan Cyclic Tag Systems. Ada banyak ruang untuk secara kreatif memilih "bahasa" lengkap turing dalam tantangan ini.
Sparr
5

garis miring dalam Python, 640 498 byte

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////

Program garis miring adalah string, dalam interpreter ini terbatas pada karakter '/' dan '\'. Dalam implementasi ini, / adalah '1' dan \ adalah '0' untuk memungkinkan bermain golf dengan menggunakan bin python (x). Ketika interpreter menemukan a \, karakter berikutnya adalah output dan kedua karakter dihapus. Ketika bertemu a /, ia mencari dan mengganti pola sebagai / search / replace / termasuk karakter yang lolos dalam pola (\\ mewakili \ dan \ / mewakili /). Operasi penggantian itu kemudian dilakukan pada string berulang kali hingga string pencarian tidak lagi ada, kemudian interpretasi berlanjut dari awal lagi. Program berhenti ketika kosong. Suatu program akan terbunuh jika ada set / pola yang tidak tertutup atau \ tanpa karakter setelahnya.

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
Sparr
sumber
4

Treehugger di Jawa, 1.299 1.257 1.251 1.207 1.203 1.201 1.193 1.189 byte

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;}}
SuperJedi224
sumber
4

BrachylogPosting masalah korespondensi , 10 byte

≜;?{~c}ᵐ\d

Cobalah online!

Fungsi yang merupakan generator yang menghasilkan semua masalah korespondensi Post yang mungkin dimana solusi brute-force akhirnya berhenti. (Solusi brute-forcing untuk masalah korespondensi Post dikenal sebagai operasi Turing-complete.) TIO link berisi header yang mengubah generator ke program penuh, dan mencetak setiap output segera seperti yang dihasilkan (dengan demikian, ketika TIO membunuh program karena memakan lebih dari 60 detik waktu eksekusi, output yang dihasilkan sejauh ini terlihat).

Ini menggunakan perumusan masalah di mana string diberikan sebagai string digit, nol terkemuka tidak diizinkan kecuali untuk 0dirinya sendiri, solusi untuk masalah yang melibatkan nol terkemuka tidak diterima, dan serangkaian digit dapat diwakili sebagai salah satu nomor , atau minus angkanya. Jelas, tidak ada yang memiliki dampak pada kelengkapan Turing bahasa (karena tidak perlu masalah korespondensi Post untuk menggunakan angka nol sama sekali).

Program ini bekerja melalui menghasilkan semua solusi yang mungkin untuk masalah, kemudian bekerja mundur untuk menemukan program asli yang diselesaikan oleh mereka. Dengan demikian, sebuah program individual dapat di-output berkali-kali. Tidak jelas apakah ini membatalkan jawaban atau tidak; Perhatikan bahwa semua program penghentian pada akhirnya akan menghasilkan setidaknya satu kali (pada kenyataannya, berkali-kali tak terhingga, karena setiap program yang memiliki solusi memiliki banyak solusi tak terhingga), dan program yang tidak berhenti akan pernah menjadi keluaran.

Penjelasan

≜;?{~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}

sumber
2

"Ungu tanpa I / O" di Ceylon, 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));}}}}

Ungu adalah bahasa satu instruksi yang memodifikasi sendiri yang diminta untuk menerjemahkan di sini . Sebagai input dan output tidak relevan untuk tugas ini, saya dihapus oarti simbol itu dari penafsir, sehingga (berpotensi) simbol berlaku hanya a, b, A, B, idan 1(yang terakhir hanya untuk membaca, bukan untuk menulis).

Tetapi karena Ungu memodifikasi sendiri (dan menggunakan kode sumbernya sebagai data), berpotensi juga program-program yang mengandung selain karakter-karakter itu berguna, jadi saya memilih untuk mengizinkan semua karakter ASCII yang dapat dicetak (bukan spasi) dalam kode (yang lain mungkin berguna juga, tetapi tidak mudah dicetak).

(Anda dapat memodifikasi penerjemah untuk alih-alih mengambil string karakter yang diizinkan sebagai argumen baris perintah - alihkan baris komentar yang dijelaskan di abawah. Kemudian panjangnya menjadi 686 byte.)

Dengan demikian, penerjemah "paralel" saya menciptakan semua string hingga dari karakter-karakter tersebut (dengan panjang yang semakin panjang dan urutan leksikografis) dan mencoba masing-masingnya.

Ungu akan berhenti tanpa kesalahan setiap kali perintah untuk dibaca dari rekaman untuk eksekusi tidak valid - sehingga tidak ada program yang tidak valid dan banyak, banyak yang berhenti. (Sebagian besar berhenti bahkan pada langkah pertama, hanya beberapa program dengan panjang 3 datang ke langkah kedua (dan akan berhenti kemudian), yang non-berhenti pertama memiliki panjang 6.

Saya pikir program non-halting pertama dalam urutan yang dicoba oleh penerjemah saya adalah aaaiaa, yang pada langkah pertama menetapkan aregister ke 0 (yang sudah ada), dan langkah kedua dan setiap langkah berikutnya mengatur penunjuk instruksi kembali ke 0, menyebabkannya dieksekusi iaalagi.

Saya menggunakan kembali bagian dari kode yang ditulis untuk penerjemah ungu "standar" saya , tetapi karena penghapusan input dan output, penerjemah paralel saya menjadi sedikit lebih pendek dari itu, sementara termasuk logika tambahan untuk menjalankan beberapa program sekaligus.

Ini adalah versi yang diomentari dan diformat:

// Find (enumerate) all halting programs in (a non-I/O subset of) Purple.
//
// Question:  /codegolf//q/51273/2338
// My answer: /codegolf//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);
    }
}
Paŭlo Ebermann
sumber
2

Kalkulus kombinator SK di Haskell , 249 byte

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)

Cobalah online!

Bagaimana itu bekerja

Aturan evaluasi panggilan demi nilai untuk kalkulus kombinator SK adalah sebagai berikut:

(a) S xyzxz ( yz ), untuk x , y , z dalam bentuk normal;
(B) K xyx , untuk x , y dalam bentuk normal;
(c) xyxy , jika xx ′;
(d) xyxy ′, untuk x dalam bentuk normal, jika yy ′ .

Karena kami hanya tertarik untuk menghentikan perilaku, kami memperluas bahasa sedikit dengan memperkenalkan simbol H yang tidak dalam bentuk normal, tetapi semua bentuk normal "mengevaluasi":

(a) S xyzxz ( yz ), untuk x , y , z dalam bentuk normal;
(B ′) K x H ↦ x , untuk x dalam bentuk normal;
(c) xyxy , jika xx ′;
(d) xyxy ′, untuk x dalam bentuk normal, jika yy ′ ;
(e) S ↦ H;
(f) K ↦ H;
(g) SH ↦ H;
(h) KH ↦ H;
(i) SHH ↦ H.

Kami menganggap setiap aplikasi H x menjadi kesalahan run-time untuk diperlakukan seolah-olah itu loop tak terbatas, dan kami memesan evaluasi sehingga tidak ada H diproduksi oleh (e) - (i) kecuali dalam konteks di mana ia akan diabaikan (tingkat atas, setiap K x ☐, setiap diabaikan K☐, setiap diabaikan S x ☐ untuk x dalam bentuk normal, setiap diabaikan S☐H). Dengan cara ini kami tidak memengaruhi perilaku berhenti dari istilah biasa yang kekurangan H.

Manfaat dari aturan-aturan yang dimodifikasi ini adalah bahwa setiap istilah yang dapat dinormalisasi memiliki jalur evaluasi unik ke H, dan bahwa setiap istilah memiliki jumlah terbatas kemungkinan preimage di bawah under. Jadi, alih-alih menggunakan pendekatan dovetailing, kita dapat melakukan pencarian pertama yang jauh lebih efisien dari semua jalur evaluasi terbalik dari H.

nmemeriksa apakah suatu istilah dalam bentuk normal, fmenemukan semua kemungkinan preimage dari suatu istilah, dan lmerupakan daftar malas dari istilah-istilah yang dapat dinormalisasi yang dihasilkan oleh pencarian pertama yang luas dari H.

Anders Kaseorg
sumber