Xuất ra mọi chương trình tạm dừng (viết trình thông dịch song song)


26

Mục tiêu của thử thách này là (cuối cùng) xuất ra mọi chương trình tạm dừng có thể bằng ngôn ngữ bạn chọn. Lúc đầu điều này nghe có vẻ bất khả thi, nhưng bạn có thể thực hiện điều này với một sự lựa chọn rất cẩn thận về thứ tự thực hiện.

Dưới đây là một sơ đồ ASCII để minh họa điều này. Để các cột biểu thị một số của mỗi chương trình có thể (mỗi chương trình là một số ký hiệu hữu hạn từ một bảng chữ cái hữu hạn). Để mỗi hàng đại diện cho một bước duy nhất trong việc thực hiện chương trình đó. Một Xđại diện cho việc thực hiện được thực hiện bởi chương trình đó tại thời điểm đó.

 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

Như bạn có thể nói, chương trình 2 và 4 không dừng lại. Nếu bạn thực hiện chúng cùng một lúc, bộ điều khiển của bạn sẽ bị kẹt trong vòng lặp vô hạn là chương trình 2 và không bao giờ xuất chương trình 3 trở lên.

Thay vào đó, bạn sử dụng một cách tiếp cận phù hợp . Các chữ cái thể hiện một thứ tự thực hiện có thể trong 26 bước đầu tiên. Các *s là nơi chương trình đã dừng lại và được xuất ra. Đây .là những bước chưa được thực hiện.

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

Yêu cầu đối với ngôn ngữ đích

Ngôn ngữ đích (ngôn ngữ được giải thích song song) phải là Turing-Complete. Ngoài ra, nó có thể là bất kỳ ngôn ngữ nào Turing-Complete, bao gồm cả các tập hợp con Turing hoàn chỉnh của các ngôn ngữ lớn hơn nhiều. Bạn cũng có thể tự do diễn giải những thứ như quy tắc hệ thống thẻ tuần hoàn. Bạn cũng được phép tạo một ngôn ngữ để kiểm tra, miễn là bạn có thể chỉ ra lý do tại sao nó hoàn thành Turing.

Ví dụ, nếu bạn chọn kiểm tra brainfuck, thì tốt nhất chỉ nên kiểm tra []-+<>tập hợp con, vì đầu vào không được hỗ trợ và đầu ra chỉ bị vứt đi (xem bên dưới).

Khi nói đến chương trình "điều khiển" (mà bạn đang chơi gôn), không có yêu cầu đặc biệt nào. Hạn chế ngôn ngữ bình thường áp dụng.

Cách tạo danh sách chương trình vô hạn

Phần lớn các ngôn ngữ lập trình có thể được biểu diễn dưới dạng một loạt các ký hiệu từ một bảng chữ cái hữu hạn. Trong trường hợp này, việc liệt kê một danh sách mọi chương trình có thể theo thứ tự độ dài là tương đối dễ dàng. Bảng chữ cái bạn sử dụng phải đại diện cho các yêu cầu của ngôn ngữ đích. Trong hầu hết các trường hợp, đây là ASCII có thể in được. Nếu ngôn ngữ của bạn hỗ trợ Unicode như một tính năng bổ sung, bạn không nên kiểm tra mọi tổ hợp ký tự Unicode có thể, chỉ ASCII. Nếu ngôn ngữ của bạn chỉ sử dụng []-+<>thì đừng kiểm tra các kết hợp khác nhau của các ký tự ASCII "bình luận". Các ngôn ngữ như APL sẽ có bảng chữ cái đặc biệt của riêng họ.

Nếu ngôn ngữ của bạn được mô tả tốt nhất theo một số cách không phải là chữ cái, như Fractran hoặc Turing Machines, thì có những phương pháp hợp lệ khác để tạo danh sách tất cả các chương trình hợp lệ có thể.

Giải thích một danh sách các chương trình ngày càng phát triển

Phần quan trọng của thách thức này là viết một trình thông dịch song song cho một danh sách các chương trình đang phát triển. Có một số bước cơ bản cho việc này:

  • Thêm số lượng chương trình hữu hạn vào danh sách
  • Giải thích từng chương trình trong danh sách riêng lẻ trong một khoảng thời gian hữu hạn. Điều này có thể được thực hiện bằng cách thực hiện một bước hướng dẫn cho mỗi bước. Lưu tất cả các trạng thái.
  • Xóa tất cả các chương trình chấm dứt / ném lỗi khỏi danh sách
  • Xuất ra các chương trình tạm dừng *
  • Thêm một số chương trình nữa vào danh sách
  • Mô phỏng lần lượt từng chương trình, chọn thực hiện các chương trình cũ hơn khi chương trình bị tắt
  • Xóa tất cả các chương trình chấm dứt / ném lỗi khỏi danh sách
  • Xuất ra các chương trình tạm dừng *
  • nói lại

* Bạn chỉ nên xuất các chương trình tạm dừng sạch sẽ. Điều này có nghĩa là không có lỗi cú pháp hoặc ngoại lệ chưa được ném trong quá trình thực thi. Các chương trình yêu cầu đầu vào cũng nên được chấm dứt mà không xuất chúng. Nếu một chương trình tạo đầu ra, bạn không nên chấm dứt nó, chỉ cần ném đầu ra đi.

Thêm quy tắc

  • Bạn không được sinh ra các luồng mới để chứa các chương trình đã thử nghiệm, vì điều này giảm tải công việc song song hóa lên hệ điều hành máy chủ / phần mềm khác.
  • Chỉnh sửa: Để đóng các lỗ hổng tiềm năng trong tương lai, bạn không được phép eval(hoặc bất kỳ chức năng liên quan nào) một phần của mã chương trình được kiểm tra . Bạn có thể eval mã hóa từ mã của trình thông dịch. (Câu trả lời BF-in-Python vẫn hợp lệ theo các quy tắc này.)
  • Đây là
  • Ngôn ngữ bạn viết bài nộp của bạn không cần phải giống với ngôn ngữ bạn đang kiểm tra / xuất ra.
  • Bạn nên cho rằng bộ nhớ khả dụng của bạn là không giới hạn.
  • Khi chứng minh tính đầy đủ của Turing, bạn có thể cho rằng đầu vào được mã hóa cứng vào chương trình và đầu ra có thể được đọc khỏi trạng thái bên trong của chương trình.
  • Nếu chương trình của bạn tự xuất ra, nó có thể sai hoặc đa âm.

7
Phải mất quá lâu để tôi nhận ra lý do"If your program outputs itself, it is probably wrong or a polyglot."
trichoplax

1
Chúng tôi có thể cho rằng bộ nhớ khả dụng là không bị ràng buộc (tôi không nghĩ điều này là có thể khác)
KSab

1
@KSab Có, và chắc chắn là không thể.
PhiNotPi

1
Thử thách tiếp theo ( khó hơn nhiều ): Xuất ra mọi chương trình không tạm dừng.
Milo Brandt

1
Có thể chấp nhận đầu ra cùng một chương trình nhiều lần không?

Câu trả lời:


9

subleq OISC trong 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

Một chương trình subleq là một danh sách mở rộng gồm các số nguyên (p) và một con trỏ lệnh (i). Biến thể subleq này sử dụng địa chỉ tương đối, mà trang thảo luận wiki gợi ý là cần thiết để đảm bảo tính hoàn chỉnh với các giá trị bị ràng buộc. Mỗi đánh dấu, thao tác p[i+p[i+1]]-=p[i+p[i]]được thực hiện và sau đó i+=p[i+2]nếu kết quả hoạt động là <= 0, nếu không i+=3. Nếu tôi bị âm, chương trình sẽ dừng lại.

Việc triển khai này kiểm tra mọi chương trình có trạng thái ban đầu bao gồm các số nguyên không âm một chữ số (0-9) với con trỏ lệnh ban đầu là 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

Đầu ra bị đảo ngược, vì lý do chơi golf. Thông số kỹ thuật ở trên có thể được trình bày ngược lại, nhưng sau đó sẽ không khớp với mã được sử dụng trong triển khai, vì vậy tôi đã không mô tả nó theo cách đó.

EDIT: Chương trình đầu tiên thể hiện sự tăng trưởng không giới hạn đơn giản là 14283, làm giảm giá trị tại vị trí bộ nhớ 6 và ghi 0 rõ ràng (trái ngược với 0 ẩn trong mỗi ô) cho ô âm tính tiếp theo, cứ sau ba tích tắc.


9

Thẻ tuần hoàn bitwise trong CJam, 98 87 84 77 byte

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

Vì đây là một vòng lặp vô hạn, bạn không thể trực tiếp kiểm tra điều này trong trình thông dịch trực tuyến. Tuy nhiên, đây là một phiên bản thay thế đọc số lần lặp từ STDIN để bạn chơi xung quanh. Để kiểm tra toàn bộ chương trình, bạn sẽ cần trình thông dịch Java .

BCT là một biến thể tối giản của Hệ thống thẻ Cyclic . Một chương trình được xác định bởi hai chuỗi nhị phân: danh sách hướng dẫn (tuần hoàn) và trạng thái ban đầu. Để làm cho cuộc sống của tôi dễ dàng hơn khi in các chương trình, tôi đã xác định ký hiệu của riêng mình: mỗi chuỗi được đưa ra dưới dạng một dãy số nguyên kiểu CJam và toàn bộ chương trình được bao quanh [[...]], ví dụ:

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

Tôi cũng không cho phép các trạng thái ban đầu trống hoặc danh sách hướng dẫn trống.

Các hướng dẫn trong BCT được diễn giải như sau:

  • Nếu hướng dẫn là 0, loại bỏ bit hàng đầu khỏi trạng thái hiện tại.
  • Nếu hướng dẫn là 1, đọc một bit khác ra khỏi danh sách hướng dẫn, gọi đó X. Nếu bit đầu từ trạng thái hiện tại là1 , nối Xvào trạng thái hiện tại, nếu không thì không làm gì cả.

Nếu trạng thái hiện tại trở nên trống rỗng, chương trình tạm dừng.

Một vài chương trình tạm dừng đầu tiên là

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

Nếu bạn muốn xem thêm, hãy xem phiên bản trong trình thông dịch trực tuyến tôi đã liên kết ở trên.

Giải trình

Đây là cách mã hoạt động. Để theo dõi sự phù hợp, chúng tôi sẽ luôn có một mảng trên ngăn xếp chứa tất cả các chương trình. Mỗi chương trình là một cặp biểu diễn bên trong của mã chương trình (như [[0 1 0] [1 0]]) cũng như trạng thái hiện tại của chương trình. Chúng tôi sẽ chỉ sử dụng cái sau để thực hiện tính toán, nhưng chúng tôi sẽ cần nhớ cái trước để in chương trình một khi nó dừng lại. Danh sách các chương trình này chỉ đơn giản được khởi tạo thành một mảng trống vớiL .

Phần còn lại của mã là một vòng lặp vô hạn {...1}g, trước tiên thêm một hoặc nhiều chương trình vào danh sách này và tính toán một bước trên mỗi chương trình. Các chương trình tạm dừng được in và xóa khỏi danh sách.

Tôi đang liệt kê các chương trình bằng cách đếm số nhị phân. Chữ số hàng đầu được loại bỏ để đảm bảo rằng chúng tôi cũng có thể nhận được tất cả các chương trình có số 0 đứng đầu. Đối với mỗi biểu diễn nhị phân bị cắt cụt như vậy, tôi đẩy một chương trình cho mỗi lần phân tách có thể có giữa các hướng dẫn và trạng thái ban đầu. Ví dụ, nếu bộ đếm hiện tại 42, đại diện nhị phân của nó là 101010. Chúng tôi thoát khỏi việc dẫn đầu 1và đẩy tất cả các mối nối không trống:

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

Vì chúng tôi không muốn các hướng dẫn hoặc trạng thái trống, chúng tôi bắt đầu truy cập ở mức 4, cung cấp [[[0] [0]]]. Việc liệt kê này được thực hiện theo mã sau:

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.

Phần còn lại của mã ánh xạ một khối vào danh sách các chương trình, thực hiện một bước tính toán BCT ở nửa sau của các cặp này và xóa chương trình nếu nó dừng:

)~     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.
}?

Đẹp (+1). Một số byte có thể được lưu bằng cách sử dụng thực tế rằng BCT đang hoàn thành Turing ngay cả khi bị hạn chế chỉ sử dụng 1 làm kho dữ liệu ban đầu ("trạng thái" của bạn). Ví dụ: diễn giải từng số nguyên dương liên tiếp trong nhị phân là 1P, sau đó thực hiện P trên 1 và đầu ra thực hiện P iff kết thúc (lại khớp với nhau). (Tất nhiên, bất kỳ P nào bắt đầu bằng 0 sau đó sẽ có trong danh sách, vì điều đó sẽ ngay lập tức xóa kho dữ liệu ban đầu.)
res

8

Brainfuck trong Python, 567 byte

Một giải pháp tương đối đơn giản, vì Brainfuck hầu như không phải là ngôn ngữ khó nhất để viết một thông dịch viên.

Việc triển khai Brainfuck này có con trỏ dữ liệu bắt đầu từ 0, chỉ được phép nhận giá trị dương (được coi là lỗi nếu nó cố gắng đi về bên trái của 0). Các ô dữ liệu có thể nhận các giá trị từ 0 đến 255 và bao bọc. 5 hướng dẫn hợp lệ là ><+[]( -không cần thiết do gói).

Tôi nghĩ rằng đầu ra bây giờ hoàn toàn chính xác, tuy nhiên khó có thể chắc chắn rằng nó đang in mọi giải pháp có thể nên tôi có thể thiếu một số.

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

Một vài thông số đầu tiên:

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

Và danh sách 2000 đầu tiên: http://pastebin.com/KQG8PVJn

Và cuối cùng là danh sách 2000 đầu ra đầu tiên có []trong đó: http://pastebin.com/iHWwJprs
(tất cả phần còn lại là tầm thường miễn là chúng hợp lệ)

Lưu ý rằng đầu ra không theo thứ tự được sắp xếp, mặc dù nó có thể xuất hiện theo cách đó đối với nhiều người trong số họ, vì các chương trình mất nhiều thời gian hơn sẽ được in sau.


1
Cả hai trần [-][+]chắc chắn sẽ xuất hiện vì nội dung của vòng lặp chỉ đơn giản là bỏ qua (không có gói liên quan).
PhiNotPi

@ Sp3000 Các [-][+]là một lỗi mà bây giờ sẽ cố định và tôi đã cập nhật với các thiết lập
KSab

1
Tại sao bạn ủng hộ .? Không cần thiết cho một tập hợp con Turing-đầy đủ của BF và đầu ra nên được bỏ qua. Ngoài ra, vì bạn đang bọc các giá trị ô xung quanh, tôi nghĩ bạn chỉ cần một -+.
Martin Ender

@ MartinBüttner Tôi dường như đã hiểu nhầm câu hỏi; Tôi đã không đọc phần 'hoàn thành tập hợp con'. Tuy nhiên, điều này không tạo ra thách thức gần như tương đương với (hầu hết) các ngôn ngữ? Bạn không thể thực hiện thay thế 1 thành 1 bằng Brainfuck (hoặc có thể đơn giản hơn nữa), ví dụ mã c ở đây: en.wikipedia.org/wiki/Brainfuck#Commands .
KSab

2
Hãy xem stackoverflow.com/questions/1053931/ Cách đặc biệt là mục OISC. Ngoài ra, xem xét CA Rule 110 và Hệ thống thẻ tuần hoàn. Có rất nhiều chỗ để sáng tạo chọn một "ngôn ngữ" hoàn chỉnh trong thử thách này.
Sparr

5

dấu gạch chéo trong 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////

Chương trình gạch chéo là một chuỗi, trong trình thông dịch này giới hạn ở các ký tự '/' và '\'. Trong triển khai này, / là '1' và \ là '0' để cho phép chơi gôn với việc sử dụng bin (x) của python. Khi trình thông dịch gặp một \, ký tự tiếp theo là đầu ra và cả hai ký tự được loại bỏ. Khi nó gặp a /, nó sẽ tìm kiếm và thay thế các mẫu như / search / thay thế / bao gồm các ký tự được thoát trong các mẫu (\ đại diện \ và \ / đại diện /). Thao tác thay thế đó sau đó được thực hiện trên chuỗi liên tục cho đến khi chuỗi tìm kiếm không còn nữa, sau đó diễn giải lại tiếp tục từ đầu. Chương trình tạm dừng khi nó trống. Một chương trình sẽ bị giết nếu có một tập hợp / mẫu không được tiết lộ hoặc \ không có ký tự nào sau nó.

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

Treehugger ở Java, 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;}}

4

BrachylogBài toán tương ứng bài , 10 byte

≜;?{~c}ᵐ\d

Hãy thử trực tuyến!

Chức năng là một trình tạo tạo ra tất cả các vấn đề tương ứng có thể có của Post mà các giải pháp cưỡng bức cuối cùng tạm dừng. (Các giải pháp cưỡng bức cho vấn đề tương ứng Post được biết là hoạt động hoàn chỉnh Turing.) Liên kết TIO chứa một tiêu đề chuyển đổi một trình tạo thành một chương trình đầy đủ và in ra từng đầu ra ngay khi nó được tạo ra (do đó, khi TIO giết chết chương trình do tiêu tốn hơn 60 giây thời gian thực hiện, đầu ra được tạo ra cho đến nay là có thể nhìn thấy).

Điều này sử dụng một công thức của vấn đề trong đó các chuỗi được đưa ra dưới dạng các chuỗi chữ số, các số 0 đứng đầu không được phép ngoại trừ 0chính nó, các giải pháp cho vấn đề liên quan đến các số 0 đứng đầu không được chấp nhận và một chuỗi các chữ số có thể được biểu thị bằng số hoặc trừ số. Rõ ràng, không có điều nào trong số này có bất kỳ tác động nào đến tính hoàn chỉnh của ngôn ngữ (vì không cần phải có vấn đề tương ứng với Post để sử dụng chữ số 0).

Chương trình này hoạt động thông qua việc tạo ra tất cả các giải pháp có thể cho các vấn đề, sau đó làm việc ngược lại để tìm các chương trình gốc được giải quyết bởi chúng. Như vậy, một chương trình riêng lẻ có thể được xuất ra nhiều lần. Không rõ điều này có làm mất hiệu lực câu trả lời hay không; lưu ý rằng tất cả các chương trình tạm dừng cuối cùng sẽ được xuất ít nhất một lần (trên thực tế, vô cùng nhiều lần, vì bất kỳ chương trình nào có giải pháp đều có vô số giải pháp) và các chương trình không tạm dừng sẽ không bao giờ được xuất.

Giải trình

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

"Màu tím không có I / O" trong 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));}}}}

Màu tím là một ngôn ngữ một hướng dẫn tự sửa đổi được yêu cầu giải thích ở đây . Như đầu vào và đầu ra là không thích hợp cho công việc này, tôi loại bỏ các oý nghĩa của biểu tượng từ người phiên dịch, như vậy mà (khả năng) ký hợp lệ chỉ a, b, A, B, i1(người cuối cùng chỉ để đọc, không phải cho văn bản).

Nhưng vì Purple tự sửa đổi (và sử dụng mã nguồn của nó làm dữ liệu), nên các chương trình có chứa các ký tự khác không hữu ích, vì vậy tôi đã chọn cho phép tất cả các ký tự ASCII có thể in (không phải khoảng trắng) trong mã (các ký tự khác có thể cũng hữu ích, nhưng không dễ in như vậy).

(Bạn có thể sửa đổi trình thông dịch để thay vào đó là chuỗi các ký tự được phép làm đối số dòng lệnh - chuyển dòng nhận xét xác định abên dưới. Sau đó, độ dài trở thành 686 byte.)

Do đó, trình thông dịch "song song" của tôi tạo ra tất cả các chuỗi hữu hạn từ các ký tự đó (theo thứ tự tăng dần và theo thứ tự từ điển) và thử từng chuỗi.

Màu tím sẽ dừng lại mà không có lỗi bất cứ khi nào lệnh được đọc từ băng để thực thi không hợp lệ - do đó không có chương trình không hợp lệ và nhiều, nhiều lệnh tạm dừng. (Hầu hết tạm dừng ngay cả ở bước đầu tiên, chỉ một số chương trình có độ dài 3 đến bước thứ hai (và sẽ dừng sau đó), những chương trình không dừng đầu tiên có độ dài 6.

Tôi nghĩ rằng chương trình không tạm dừng đầu tiên theo thứ tự mà trình thông dịch của tôi đã thử là aaaiaa, trong bước đầu tiên đặt thanh aghi thành 0 (đã có), và bước thứ hai và mỗi bước tiếp theo đặt con trỏ lệnh trở về 0, khiến nó thực thi iaalại.

Tôi đã sử dụng lại một phần mã được viết cho trình thông dịch màu tím "tiêu chuẩn" của mình , nhưng do loại bỏ đầu vào và đầu ra, trình thông dịch song song của tôi thậm chí còn ngắn hơn một chút, trong khi bao gồm logic bổ sung để thực thi nhiều chương trình cùng một lúc.

Đây là một phiên bản nhận xét và định dạng:

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

Tính toán tổ hợp SK trong 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)

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

Các quy tắc đánh giá cuộc gọi theo giá trị cho phép tính tổ hợp SK như sau:

(a) S xyzxz ( yz ), cho x , y , z trong hình thức bình thường;
(b) K xyx , với x , y ở dạng bình thường;
(c) xyxy , nếu xx ′;
(d) xyxy ', cho x trong hình thức bình thường, nếu yy' .

Vì chúng tôi chỉ quan tâm đến việc tạm dừng hành vi, chúng tôi mở rộng ngôn ngữ một chút bằng cách giới thiệu một biểu tượng H không ở dạng bình thường, nhưng tất cả các hình thức bình thường, đánh giá, đánh giá:

(a) S xyzxz ( yz ), cho x , y , z trong hình thức bình thường;
(b) K x H x , với x ở dạng bình thường;
(c) xyxy , nếu xx ′;
(d) xyxy ', cho x trong hình thức bình thường, nếu yy' ;
(e) S H;
(f) K H;
(g) SH ↦ H;
(h) KH H;
(i) SHH ↦ H.

Chúng tôi coi bất kỳ ứng dụng H x nào là lỗi thời gian chạy được xử lý như thể đó là một vòng lặp vô hạn và chúng tôi yêu cầu các đánh giá sao cho không có H được tạo bởi (e) - (i) ngoại trừ trong bối cảnh nó sẽ xảy ra bị bỏ qua (cấp cao nhất, bất kỳ K x ☐, bất kỳ K☐ bị bỏ qua, bất kỳ S x ignored bị bỏ qua cho x ở dạng bình thường, bất kỳ S☐H bị bỏ qua). Bằng cách này, chúng tôi không ảnh hưởng đến hành vi tạm dừng của các điều khoản thông thường thiếu H.

Lợi ích của các quy tắc được sửa đổi này là mọi thuật ngữ chuẩn hóa đều có đường dẫn đánh giá duy nhất đến H và mọi thuật ngữ đều có số lượng giới hạn có thể có trong possible. Vì vậy, thay vì sử dụng phương pháp khớp nối, chúng ta có thể thực hiện tìm kiếm theo chiều rộng hiệu quả hơn nhiều so với tất cả các đường dẫn đánh giá ngược từ H.

nkiểm tra xem một thuật ngữ có ở dạng bình thường hay không, ftìm thấy tất cả các tiền đề có thể có của một thuật ngữ và llà một danh sách vô hạn lười biếng của các thuật ngữ chuẩn hóa được tạo ra bởi tìm kiếm đầu tiên từ H.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.