모든 정지 프로그램 출력 (병렬 인터프리터 작성)


26

이 과제의 목표는 가능한 모든 정지 프로그램을 원하는 언어 로 (결과적으로) 출력 하는 것입니다. 처음에는 이것이 불가능한 것처럼 들릴 수 있지만 실행 순서를 매우 신중하게 선택하여이를 달성 할 수 있습니다.

아래는이를 설명하기위한 ASCII 다이어그램입니다. 열은 가능한 모든 프로그램의 번호를 나타냅니다 (각 프로그램은 유한 알파벳의 한정된 수의 기호입니다). 각 행이 해당 프로그램 실행의 단일 단계를 나타내도록하십시오. 은 X시간 단계에서 해당 프로그램에 의해 수행되는 실행을 나타낸다.

 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

알 수 있듯이 프로그램 2와 4는 중단되지 않습니다. 한 번에 하나씩 실행하면 컨트롤러가 프로그램 2 인 무한 루프에 갇히고 프로그램 3 이상을 출력하지 않습니다.

대신 더브 테일 방식 을 사용합니다 . 문자는 처음 26 단계의 가능한 실행 순서를 나타냅니다. *의 해당 프로그램은 중단하고 출력 장소입니다. .들 아직 실행되지 않은 단계입니다.

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

대상 언어에 대한 요구 사항

대상 언어 (병렬 해석)는 Turing-complete 여야합니다. 그 외에는 훨씬 큰 언어의 Turing-complete 하위 세트를 포함하여 Turing-complete 인 모든 언어가 될 수 있습니다 . 순환 태그 시스템 규칙과 같은 것을 자유롭게 해석 할 수도 있습니다. 튜링이 완료된 이유를 보여줄 수있는 한 테스트 할 언어를 만들 수도 있습니다.

예를 들어, brainfuck을 테스트하기로 선택한 경우 []-+<>입력이 지원되지 않고 출력이 버려지기 때문에 서브 세트 만 테스트하는 것이 가장 좋습니다 (아래 참조).

"컨트롤러"프로그램 (골프하는 프로그램)에 대해서는 특별한 요구 사항이 없습니다. 일반적인 언어 제한이 적용됩니다.

무한한 프로그램 목록을 만드는 방법

대부분의 프로그래밍 언어는 유한 알파벳의 일련의 기호로 표시 될 수 있습니다. 이 경우 길이를 늘리는 순서대로 가능한 모든 프로그램 목록을 열거하는 것이 상대적으로 쉽습니다. 사용하는 알파벳 은 대상 언어 의 요구 사항 을 나타내야 합니다. 대부분의 경우 이것은 인쇄 가능한 ASCII입니다. 언어가 추가 기능으로 유니 코드를 지원하는 경우 ASCII 만 가능한 모든 유니 코드 문자 조합을 테스트하지 않아야합니다. 사용하는 언어 만 사용하는 경우 []-+<>"주석"ASCII 문자의 다양한 조합을 테스트하지 마십시오. APL과 같은 언어에는 자체 특수 알파벳이 있습니다.

언어가 Fractran 또는 Turing Machines와 같이 알파벳이 아닌 방식으로 가장 잘 설명되어 있으면 가능한 모든 유효한 프로그램 목록을 생성하는 다른 동일한 방법이 있습니다.

점점 늘어나는 프로그램 목록 해석

이 과제의 핵심 부분은 점점 늘어나는 프로그램 목록에 대해 병렬 인터프리터를 작성하는 것입니다. 이를위한 몇 가지 기본 단계가 있습니다.

  • 한정된 수의 프로그램을 목록에 추가
  • 한정된 기간 동안 목록의 각 프로그램을 개별적으로 해석하십시오. 이는 각각에 대해 하나의 명령 단계를 수행하여 수행 할 수 있습니다. 모든 상태를 저장하십시오.
  • 목록에서 종료 / 오류 발생 프로그램을 모두 제거하십시오.
  • 깨끗하게 정지 된 * 프로그램 출력
  • 더 많은 프로그램을 목록에 추가
  • 각 프로그램을 차례로 시뮬레이션하여 중단 된 이전 프로그램의 실행을 선택합니다.
  • 목록에서 종료 / 오류 발생 프로그램을 모두 제거하십시오.
  • 깨끗하게 정지 된 * 프로그램 출력
  • 반복

* 정지 된 프로그램 만 출력하십시오. 이는 실행 중에 구문 오류나 포착되지 않은 예외가 발생하지 않았 음을 의미합니다. 입력을 요구하는 프로그램도 출력하지 않고 종료해야합니다. 프로그램이 출력을 생성하면 종료하지 말고 출력을 버려야합니다.

더 많은 규칙

  • 테스트 된 프로그램을 포함하기 위해 새 스레드를 생성해서는 안됩니다. 이렇게하면 병렬 작업이 호스트 OS / 기타 소프트웨어로 오프로드됩니다.
  • 편집 : 미래의 허점을 막기 eval위해 테스트 된 프로그램 코드의 일부를 허용하지 않습니다 . 인터프리터 코드에서 코드 블록 있습니다eval . (BF-in-Python 답변은이 규칙에 따라 여전히 유효합니다.)
  • 이것은
  • 제출 한 언어는 테스트 / 출력하는 언어와 같을 필요 는 없습니다 .
  • 사용 가능한 메모리가 무한하다고 가정해야합니다.
  • Turing-completeness를 증명할 때 입력이 프로그램에 하드 코딩되고 프로그램의 내부 상태에서 출력을 읽을 수 있다고 가정 할 수 있습니다.
  • 프로그램이 자체적으로 출력되면 잘못되었거나 폴리 글 롯일 수 있습니다.

7
이유를 깨닫는 데 너무 오래 걸렸습니다"If your program outputs itself, it is probably wrong or a polyglot."
trichoplax

1
사용 가능한 메모리가 무한하다고 가정 할 수 있습니다 (그렇지 않다고 생각하지 않습니다)
KSab

1
@KSab 네, 그렇지 않으면 분명히 불가능합니다.
PhiNotPi

1
후속 과제 ( 매우 어렵다) : 정지하지 않는 모든 프로그램을 출력합니다.
Milo Brandt 2016 년

1
동일한 프로그램을 두 번 이상 출력 할 수 있습니까?

답변:


9

Python의 subleq OISC, 317 269 ​​바이트

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

subleq 프로그램은 확장 가능한 정수 목록 (p)과 명령어 포인터 (i)입니다. 이 subleq 변종은 상대 주소 지정을 사용하는데, 이는 위키 대화 페이지에서 제한된 값을 가진 완전한 완성을 위해 필요하다고 제안합니다. 각 틱, 작업 p[i+p[i+1]]-=p[i+p[i]]이 수행 된 다음 i+=p[i+2]작업 결과가 <= 0 인 경우 그렇지 않으면 i+=3. 내가 음수이면 프로그램이 중지됩니다.

이 구현은 초기 상태가 1의 음이 아닌 정수 (0-9)로 구성된 모든 프로그램을 초기 명령 포인터 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

골프 때문에 출력이 반전됩니다. 위의 사양은 반대로 되돌릴 수 있지만 구현에 사용 된 코드와 일치하지 않으므로 설명하지 않았습니다.

편집 : 간단한 무한 성장을 나타내는 첫 번째 프로그램은 14283이며 메모리 위치 6의 값을 낮추고 세 개의 틱마다 매 다음 틱 셀에 명시 적 0 (모든 셀의 암시 적 0과 반대)을 씁니다.


9

CJam의 비트 단위 순환 태그 , 98 87 84 77 바이트

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

이것은 무한 루프이기 때문에 온라인 인터프리터에서 직접 테스트 할 수 없습니다. 그러나 여기에 STDIN에서 반복 횟수를 읽는 대체 버전 이 있습니다. 전체 프로그램을 테스트하려면 Java 인터프리터 가 필요 합니다 .

BCT는 Cyclic Tag Systems 의 최소 ​​변형입니다 . 프로그램은 두 개의 이진 문자열, 즉 (순환) 명령어 목록과 초기 상태로 정의됩니다. 프로그램을 인쇄 할 때 삶을 편하게하기 위해, 나는 고유 한 표기법을 정의했습니다. 각 문자열은 CJam 스타일의 정수 배열로 제공되며 전체 프로그램은 다음과 같이 둘러싸입니다 [[...]].

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

빈 초기 상태 또는 빈 명령 목록도 허용하지 않습니다.

BCT의 지침은 다음과 같이 해석됩니다.

  • 명령어가 0인 경우 현재 상태에서 선행 비트를 제거하십시오.
  • 명령어가 1이면 명령어 목록에서 다른 비트를 읽으십시오 X. 현재 상태의 선행 비트가 인 경우 현재 상태 1에 추가 X하고 그렇지 않으면 아무 작업도 수행하지 않습니다.

현재 상태가 비어 있으면 프로그램이 중지됩니다.

처음 몇 개의 정지 프로그램은

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

자세한 내용을 보려면 위에 링크 된 온라인 통역사의 버전을 확인하십시오.

설명

코드 작동 방식은 다음과 같습니다. 더브 테일링을 추적하기 위해 항상 모든 프로그램을 포함하는 스택에 배열을 갖게됩니다. 각 프로그램은 프로그램 코드의 내부 표현 (예 :)과 프로그램 [[0 1 0] [1 0]]의 현재 상태 쌍입니다 . 우리는 후자를 사용하여 계산을 수행하지만 프로그램이 중지되면 인쇄하도록 전자를 기억해야합니다. 이 프로그램 목록은로 빈 배열로 초기화됩니다 L.

나머지 코드는 {...1}g하나 이상의 프로그램을 먼저이 목록에 추가하고 각 프로그램에서 한 단계를 계산 하는 무한 루프 입니다. 중단 된 프로그램이 인쇄되고 목록에서 제거됩니다.

이진수를 세어 프로그램을 열거하고 있습니다. 선행 숫자는 0을 갖는 모든 프로그램을 얻을 수 있도록 제거됩니다. 이러한 잘린 이진 표현 각각에 대해 명령과 초기 상태 사이의 가능한 분할마다 하나의 프로그램을 푸시합니다. 예를 들어 카운터가 현재 있으면 42이진 표현은 101010입니다. 우리는 선행을 제거 1하고 비어 있지 않은 모든 분할을 푸시합니다.

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

빈 명령이나 상태를 원하지 않기 때문에 카운터는 4에서 시작합니다 [[[0] [0]]]. 이 열거는 다음 코드에 의해 수행됩니다.

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.

나머지 코드는 프로그램 목록에 블록을 매핑합니다.이 목록은이 쌍의 후반부에서 BCT 계산의 한 단계를 수행하고 프로그램이 중지되면 제거합니다.

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

니스 (+1). 초기 데이터 문자열 ( "상태")로 1 만 사용하도록 제한되어 있어도 BCT가 Turing complete라는 사실을 사용하여 일부 바이트를 저장할 수 있습니다. 예를 들어, 이진수의 각 양의 정수를 1P로 해석 한 다음 1에서 P를 실행하고 Piff 실행을 종료합니다 (다시 시작). (물론, 0으로 시작하는 P는 목록에있을 것입니다. 왜냐하면 초기 데이터 문자열을 즉시 삭제하기 때문입니다.)
res

8

Python의 Brainfuck, 567 바이트

Brainfuck은 인터프리터를 작성하기에 가장 어려운 언어이므로 비교적 간단한 솔루션입니다.

이 Brainfuck 구현은 0부터 시작하는 데이터 포인터를 가지며 양의 값만 허용합니다 (0의 왼쪽으로 가려고하면 오류로 간주 됨). 데이터 셀은 0에서 255 사이의 값을 사용하여 줄 바꿈 할 수 있습니다. 유효한 5 가지 지침이 있습니다 ><+[]( -포장으로 인해 필요하지 않음).

출력이 모두 정확하다고 생각하지만 가능한 모든 솔루션을 인쇄하여 일부를 누락했는지 확인하기는 어렵습니다.

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

처음 몇 가지 출력 :

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

그리고 첫 번째 2000 목록 : http://pastebin.com/KQG8PVJn

그리고 마지막으로 처음 2000 출력 목록 []그들 : http://pastebin.com/iHWwJprs
(나머지는 모두 long로서 사소한들이있는 거 유효로)

시간이 오래 걸리는 프로그램은 나중에 인쇄되므로 출력은 정렬 된 순서가 아닙니다.


1
루프의 내용이 단순히 건너 뛰기 때문에 래핑이 필요하지 않으므로 베어 [-][+]분명히 나타납니다.
PhiNotPi 2016 년

@ SP3000 [-]과는 [+]이제 고정해야 버그를했고 나는 설정으로 업데이트 한
KSab

1
왜 지원하고 .있습니까? BF의 Turing-complete 하위 세트는 필요하지 않으며 출력은 무시해야합니다. 또한 셀 값을 래핑하므로 -and 중 하나만 필요하다고 생각합니다 +.
Martin Ender 2016 년

@ MartinBüttner 나는 그 질문을 오해 한 것 같다; 나는 'turing complete subset'부분을 읽지 않았다. 그러나 이것이 도전이 (대부분의) 언어와 거의 동등하지 않습니까? Brainfuck (또는 아마도 더 간단한 것)로 일대일 교체를 할 수 없었습니다 (예 : c . 여기 : en.wikipedia.org/wiki/Brainfuck#Commands) .
KSab

2
stackoverflow.com/questions/1053931/… 특히 OISC 항목을 살펴보십시오 . 또한 CA Rule 110 및 Cyclic Tag Systems를 살펴보십시오. 이 과제에서 튜링 완료 "언어"를 창의적으로 선택할 수있는 여지가 많이 있습니다.
Sparr

5

파이썬에서 슬래시, 640 498 바이트

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

슬래시 프로그램은 문자열이며,이 인터프리터에서 '/'및 '\'문자로 제한됩니다. 이 구현에서 /는 '1'이고 \는 '0'으로 파이썬의 bin (x)을 사용하여 골프를 할 수 있습니다. 인터프리터가 \를 만나면 다음 문자가 출력되고 두 문자가 모두 제거됩니다. /를 만나면 패턴 내에서 이스케이프 문자를 포함하여 / search / replace /로 검색을 찾고 패턴을 바꿉니다 (\\는 \를 나타내고 \ /는 /를 나타냄). 그런 다음 검색 문자열이 더 이상 존재하지 않을 때까지 해당 대체 작업이 문자열에서 반복적으로 수행 된 다음 해석이 처음부터 계속됩니다. 프로그램이 비어 있으면 중지됩니다. 닫히지 않은 / patterns 세트 또는 그 뒤에 문자가없는 \가 있으면 프로그램이 종료됩니다.

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의 Treehugger , 1,299 1,257 1,251 1,207 1,203 1,201 1,193 1,189 바이트

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

Brachylog게시물 통신 문제 , 10 바이트

≜;?{~c}ᵐ\d

온라인으로 사용해보십시오!

무차별 강제 해결 솔루션이 결국 중단되는 모든 가능한 Post 대응 문제를 생성하는 생성기입니다. (포스트 서신 문제에 대한 강제 강제 솔루션은 Turing-complete 작업으로 알려져 있습니다.) TIO 링크에는 생성기를 전체 프로그램으로 변환하는 헤더가 포함되어 있으며 생성 된대로 각 출력을 즉시 인쇄합니다 (따라서 TIO가 종료되면 60 초 이상의 실행 시간을 소비하여 지금까지 생성 된 출력을 볼 수있는 프로그램).

이것은 문자열이 자릿수 문자열로 제공되는 문제의 공식화를 사용하며, 0그 외에는 선행 0이 허용되지 않으며, 선행 0 과 관련된 문제에 대한 솔루션은 허용되지 않으며 숫자 문자열은 숫자 중 하나로 표시 될 수 있습니다 또는 숫자를 뺀 값입니다. 분명히,이 중 어느 것도 언어의 Turing-completeness에 영향을 미치지 않습니다 (Post 서신 문제가 숫자 0을 전혀 사용하지 않기 때문에).

이 프로그램은 문제에 대한 가능한 모든 솔루션을 생성 한 다음 이전 버전으로 작업하여 문제가 해결 된 원래 프로그램을 찾습니다. 따라서 개별 프로그램을 여러 번 출력 할 수 있습니다. 이것이 답변을 무효화하는지 여부는 확실하지 않습니다. 모든 중지 프로그램은 결국 한 번 이상 (실제로 솔루션이있는 프로그램이 무한히 많은 솔루션을 갖기 때문에 무한히 여러 번 출력 됨) 중단되지 않는 프로그램은 출력되지 않습니다.

설명

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

실론의 "I / O없는 자주색", 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));}}}}

퍼플여기에서 해석하도록 요청 된 자체 수정 형 단일 명령 언어입니다 . 입력과 출력이 작업 관련이없는, 나는 제거 o(잠재적으로) 유효한 기호는 단지이되도록, 인터프리터에서 기호의 의미를 a, b, A, B, i1(쓰기 단지 읽기위한 마지막이 아니라).

그러나 Purple은 자체 수정 (및 소스 코드를 데이터로 사용)하므로 잠재적으로 해당 문자 이외의 다른 프로그램도 유용하므로 코드에 인쇄 가능한 (공백이 아닌) ASCII 문자를 모두 허용하도록 선택했습니다 (다른 문자는 유용하지만 쉽게 인쇄되지는 않습니다).

(대신 통역사를 허용 된 문자열로 대신 명령 행 인수로 사용할 수 a있습니다. 아래에 정의 된 주석 행을 전환하십시오 . 그러면 길이는 686 바이트가됩니다.)

내 "병렬"인터프리터는 따라서 해당 문자에서 모든 유한 문자열을 길이와 사전 순으로 증가시켜 각각을 시도합니다.

실행을 위해 테이프에서 읽을 명령이 유효하지 않을 때마다 자주색은 오류없이 정지합니다. 따라서 유효하지 않은 프로그램이없고 정지하는 많은 프로그램이 없습니다. (첫 번째 단계에서도 대부분 중단됩니다. 길이가 3 인 프로그램 중 일부만 두 번째 단계에 도달 한 다음 중단됩니다. 첫 번째 중지되지 않은 프로그램의 길이는 6입니다.

제 인터프리터가 시도한 순서대로 첫 번째 중지하지 않는 프로그램 aaaiaa은 첫 번째 단계에서 a레지스터를 0으로 설정 하고 두 번째 및 모든 다음 단계에서 명령 포인터를 다시 0으로 설정합니다. iaa다시 실행되게 합니다.

나는 "standard"Purple의 인터프리터를 위해 작성된 코드의 일부를 재사용 했지만, 입력과 출력이 제거되어 병렬 인터프리터는 그보다 약간 짧아지고 동시에 여러 프로그램을 실행하기위한 추가 로직이 포함됩니다.

다음은 주석이 달린 형식화 된 버전입니다.

// 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);
    }
}

2

SK의 콤비 미적분학 에서 하스켈 , 249 바이트

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)

온라인으로 사용해보십시오!

작동 원리

SK 결합기 미적분에 대한 값별 호출 평가 규칙은 다음과 같습니다.

(a) x , y , z 에 대해 S xyzxz ( yz ) ; (b) K xyx , x의 경우 , y , 정규 형태의 y ; (c) XYX ' , Y , 만약 XX '; (d) XYXY '용 X 정규형 경우에 YY' .


우리는 행동을 멈추는 데에만 관심이 있기 때문에 일반적인 형태는 아니지만 모든 일반적인 형태가“평가”되는 기호 H를 도입하여 언어를 약간 확장합니다.

(a) S xyzxz ( yz ), x , y , z 에 대해 정상 형태;
(b ') K는 X H는 ↦ X 에 대한 X 정규형;
(c) XYX ' , Y , 만약 XX ';
(d) XYXY '용 X 정상적인 형태로, 만일 YY' ;
(e) S↦H;
(f) K↦H;
(g) SH↦H;
(h) KH↦H;
(i) SHH ↦ H.

우리는 응용 프로그램 H x 가 무한 루프 인 것처럼 취급되는 런타임 오류라고 생각하고, H가 발생하는 상황을 제외하고는 (e)-(i)에 의해 H가 생성되지 않도록 평가를 주문합니다. 무시 (최상위 모든 K X ☐ 어떤 무시 K☐ 어떤 무시 S X ☐위한 X 정규형, 임의 S☐H 무시). 이런 식으로 우리는 H가없는 일반적인 용어의 정지 동작에 영향을 미치지 않습니다.

이러한 수정 된 규칙의 장점은 모든 정규화 가능한 용어가 H에 대한 고유 한 평가 경로를 가지며 모든 용어가 ↦에서 한정된 수의 사전 이미지를 갖는다는 것입니다. 따라서 도브테일 방식을 사용하는 대신 H의 모든 역 평가 경로를 훨씬 더 효율적으로 탐색 할 수 있습니다.

n용어가 정규형인지 확인 f하고 가능한 모든 사전 이미지를 찾은 다음 lH에서 너비 우선 탐색을 통해 생성 된 정규화 가능한 용어의 무한한 목록입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.