깨끗한 세상을 가라 앉히다


16

이 도전은 Helka Homba프로그래밍 원시 세계 프로그래밍에 근거합니다 . 그 질문에서 원시 프로그램의 정의는 다음과 같습니다.

원시 프로그램 을 오류 자체는 없지만 N 문자의 연속 된 하위 문자열을 제거하여 수정하면 오류가 발생하는 프로그램 으로 정의 해 봅시다 1 <= N < program length.

예를 들어, 3 자 파이썬 2 프로그램

`8`

깨끗한 프로그램입니다 ( 감사, SP는 ) 모든 길이 1 원인 오류 문자열 제거로 인한 프로그램 (사실 구문 오류 만 할 것 오류의 유형) 때문에 :

8`
``
`8

또한 길이가 2 인 하위 문자열을 제거하면 발생하는 모든 프로그램에서 오류가 발생합니다.

`
`

예를 들어, 오류 가없는 `8프로그램 인 경우 부분 문자열 제거의 모든 결과가 오류 여야 `8`하므로 원시적이지 않습니다 .

노트:

  • 컴파일러 경고는 오류로 간주되지 않습니다.
  • 에러가 발생한 서브 프로그램은 결과에 상관없이 에러가 발생하는 한 입력을 받거나 출력하거나 다른 작업을 수행 할 수 있습니다.

귀하의 작업은 자체 소스 코드를 정확하게 인쇄하고 적절한 quine 규칙을 따르고 깨끗한 제로가 아닌 길이의 프로그램을 만드는 것 입니다.

각 언어에 대한 가장 짧은 대답은 바이트입니다.


오류가없는 언어는 경쟁 할 수 없다고 가정하고 있습니까?
ATaco

@ATaco 불행하게도 그렇습니다. lisp와 같은 다른 언어는 유용한 원시 프로그램을 만드는 것이 불가능한 방식으로 구문을 구성합니다.
Shelvacu

실제 /
진실한

‘각 언어마다 가장 빠른 답은 바이트입니다.’ 깨끗한 프로그램을위한 최고의 척도가 될지는 확신 할 수 없습니다.
P. Siehr

@ P.Siehr 대신 무엇을 추천 하시겠습니까?
Shelvacu

답변:


6

하스켈 , 132 바이트

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

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

이것은 quine의 확장입니다

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

데이터 문자열을 인용 된 버전 (을 사용하여 show)으로 연결하고 결과를 인쇄하여 작동합니다. 그러나 데이터 문자열의 모든 문자를 오류없이 제거 할 수 있고 $(++)<*>show$또는 (++)<*>프로그램이 중단되지 않고 또는 일부를 삭제할 수 있으므로 이는 원시적 인 것이 아닙니다 .

이 문제를 해결하기 위해 q지정된 문자열의 길이를 확인하고 fail132보다 짧은 경우 호출 하는 사용자 정의 인쇄 기능 이 정의됩니다. 이렇게하면 데이터 문자열에서 시퀀스가 ​​제거되고 $(++)<*>show$또는 (++)<*>두 경우 모두 결과가 제거됩니다. 전달 된 문자열 q이 더 짧습니다.

에서 q수를 132단축 할 수있다 1, 13, 32또는 2, 그러나 각각의 경우에 다시 fail호출된다.

내가 알 수있는 한, 다른 하위 문자열을 제거하면 구문이나 유형 오류가 발생하므로 프로그램은 처음에는 컴파일되지 않습니다. (Haskell의 엄격한 유형 시스템이 여기에 편리합니다.)

편집 : 결함을 지적한 Ørjan Johansen과 Shelvacu에게 감사드립니다!


난 두려워 fail[]|length x/=122제거 할 수 있습니다. fail[]:[putStr x|length x==122]더 잘 작동 할 수 있습니다.
Ørjan Johansen

아아, 그럼 |length x==122제거 할 수 있습니다. if length x==122 then putStr x else fail[]혹시?
Ørjan Johansen

@ ØrjanJohansen 좋은 캐치, 나는 if then else전에 그것을 가지고 있지만 그것을 줄일 수 있다고 생각했다.
Laikoni

2
putStr x될 수 있습니다 p x내가 살해하기 전에 나는 아주 긴 시간 동안 내 시스템으로 실행에 시도하는 때, 나는 그래서 무한 루프의 꼬리 호출 재귀 최적화 된 생각한다. 나는 그것을 고치는 방법에 대한 제안을 할 충분한 haskell을 모른다.
Shelvacu

@Shelvacu Whoops. 이름 p을 바꾸면 q문제가 해결됩니다.
Ørjan Johansen

4

파이썬 3 , 113 바이트

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

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

작동 원리

우리는 두 번째 문장을 삭제할 수 있기 때문에 여러 문장을 쉽게 사용할 수 없으므로 단일 표현식 quine으로 시작합니다.

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

부분 문자열 삭제로부터 보호하기 위해 open(1,"w").write대신을 사용 합니다 print. 파이썬 3에서는 write쓰여진 문자 수를 반환하는데 113, 문자열의 일부가 삭제되지 않았는지 확인합니다. 딕셔너리에서 리턴 값을 찾아서 {113:[]}결과를 for[]in…:a반복하면 빈 iterable을 얻지 못하거나 for명령문이 삭제 되면 실패합니다 .


1
코드 작동 방식에 대해 설명해 주시겠습니까?
Shelvacu

@Shelvacu 그래, 추가했다.
Anders Kaseorg

3

루비, 78 바이트

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

나는 그것을 가능하게하는 도전을 생각할 때 이것을 썼다. 원래의 원래 도전에 대한 내 대답 중 하나 에서 동일한 "래퍼"를 사용합니다 .

설명:

  • eval(*[ expr ])

    이것은 루비 프로그램으로 리턴되는 코드를 평가 합니다. 이것은 코드가 반환 하는 문자열이 유효한 루비 프로그램 인지 효과적으로 테스트합니다 . 편리하게, 루비 프로그램은 공백이거나 공백만으로 구성 될 수 있습니다.

    "splat"연산자 *를 사용하면 배열을 함수의 인수로 사용할 수 있습니다. 또한 eval제거하면 결과 프로그램은 (*[ expr ]) 이며 유효한 루비가 아닙니다.

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

    $> STDOUT의 짧은 변수입니다.

    $>.write(foo) STDOUT에 foo를 쓰고이 코드에 대해 중요한 바이트 수를 리턴합니다.

    $>.write(foo)-78: 78프로그램의 길이는 다음과 같습니다. 따라서 프로그램이 엉망이되지 않으면 기록 된 바이트 수도됩니다. 따라서 엉킴이없는 경우 0을 반환합니다.

    num.chrnum을 문자로 반환합니다. 예를 들어 0.chr단일 null 바이트를 포함하는 문자열을 반환합니다. 얽 히지 않은 프로그램에서 이것은 단일 null 바이트가있는 문자열을 제공합니다.이 문자열 eval은 no-op 인 유효한 루비 프로그램입니다.

    또한 프로그램은 부분 문자열을 제거하여 그냥 eval(*[(78).chr])또는 eval(*[(8).chr])입니다. 즉, 숫자 상수는 숫자 (0, 4, 9, 10, 11, 12, 13, 26, 32, 35, 48)로 끝날 수 없습니다. , 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 64, 95)는 유효한 단일 문자 루비 프로그램에 대한 ASCII 코드이기 때문입니다.

  • %{ str }

    이것은 루비의 문자열 리터럴에 대한 덜 알려진 구문입니다. 여기서 사용되는 이유 {}는 문자열 내에서 균형 쌍을 사용할 수 있기 때문에이 구문에 자체를 포함 할 수 있다는 것입니다. 예를 %{foo{bar}}들어와 같습니다 "foo{bar}".

  • (s=%{ 데이터 })%s

    이것은 s이 quine의 데이터 인 변수 를 printf 문자열로 정의합니다.

    루비의 할당은 할당 된 것을 반환하므로 이것은 처음 할당 s하고 실행 하는 것과 같습니다.s%s

    %끈에는 루비의 sprintf에 해당하는 합성 설탕이 있습니다. %s데이터 내의 데이터 자체가 포함 된 의미한다.

    이 코드 비트는 quine의 데이터 부분을 정의하고 전체 코드를 작성하기 위해 자체 내에 포함합니다.


3

표준 ML (MLton) , 204 (182) 189 바이트

val()=hd[(fn s=>let val$ =s^"\""^String.toString s^"\"]"val(189,%)=(size$,$)in print%end)"val()=hd[(fn s=>let val$ =s^\"\\\"\"^String.toString s^\"\\\")\"val(189,%)=(size$,$)in print%end)"]

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

MLton를 들어, 전체 SML 프로그램 중 하나에 의해 구분 및 종료 표현식 ;(예 : print"Hello";print"World";포함) 또는 선언 varfun키워드 (예 var _=print"Hello"var _=print"World") _또한 모든 변수의 이름으로 대체 할 수있는 와일드 카드이다는.

첫 번째 옵션은 ;자체적으로 유효한 프로그램 이므로 아무것도하지 않지만 오류는 발생하지 않기 때문에 원시 프로그래밍에는 쓸모 가 없습니다. 두번째 접근 방식의 문제는 같은 선언 var _=print"Hello"을 단축 할 수있는 것과 var _="Hello"(또는 var _=print)을 선언하기 때문에 var긴 우측만큼 작품 유효한 SML 식 또는 값 (기능 수 있도록 SML는, 기능적인 언어이다 값으로도 사용됨).

이 시점에서 우연히-선언에서 패턴 일치 를 우연히 발견했을 때 SML에서 원시 프로그래밍을 불가능하게 선언 할 준비가되었습니다 val. 선언의 구문은가 val <variable_name> = <expression>아니라 val <pattern> = <expression>패턴이며 변수 이름, 상수 및 생성자로 구성 될 수 있습니다. 는 AS print기능 유형을 가지고 string -> unit, 우리는에 패턴 일치를 사용할 수 있습니다 unit- 값 ()인쇄 기능이 실제로 문자열에 적용되어 시행 : val()=print"Hey". 이 방법을 어느 제거 print또는 "Hey"A의 결과 Pattern and expression disagree-error.

이러한 원시 인쇄 방식을 사용하면 다음 단계는 퀴네를 작성하는 것입니다. 마지막으로 저장 보호 기능을 추가해야합니다. 이전에는 쉬운 SML quine 기술을 사용 했지만 ( 개정 기록 참조 ) Anders Kaseorg는 자신의 경우 일부 바이트를 절약 할 수있는 다른 접근 방식을 지적했습니다. 내장 String.toString함수를 사용하여 문자열 이스케이프를 처리하고 일반적인 형식 <code>"<data>"이며 여기서 "<data>"이스케이프 된 문자열은 다음과 code같습니다.

val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"

이것은 작동하는 헛소리이지만 아직 깨끗하지는 않습니다. 우선 Anders Kaseorg는 MLton이 작은 따옴표 "를 오류없이 코드로 받아들이는 것을 발견했습니다. 즉 , 위와 같이 따옴표로 끝나는 코드를 가질 수 없습니다. 이를 방지하는 가장 짧은 방법 val()=은 괄호로 묶은 후 모든 것을 래핑하는 것이지만 코드를로 줄일 수 있습니다 val()=(). 내가 찾은 두 번째 가장 짧은 방법은을 사용하는 것입니다 val()=hd[ ... ]. 즉, 모든 것을 목록으로 묶고 첫 번째 요소를 반환하여 형식 검사기를 행복하게 만듭니다.

데이터 문자열의 일부를 눈치 채지 않고 제거 할 수 없도록하기 위해 val선언 에서 패턴 일치를 다시 사용하면 편리합니다. 인쇄 할 최종 문자열의 길이 (및 프로그램 길이)는 195와 같아야합니다. 대신에 추상화 let val t=... val 195=size t in print t end의 본문에 쓸 수 있습니다 . 문자열의 일부를 제거하면 길이가 189보다 작으므로 예외가 발생합니다.fnprint(...)Bind

여전히 문제가 남아 있습니다. 전체 val 195=size t검사를 간단히 취소 할 수 있습니다. : 우리는 튜플에 일치의 체크를 확장하여이 문제를 방지 할 수 있습니다 val t=... val(216,u)=(n+size t,t)in print u end, 언 바운드 변수에 검사 결과를 제거하도록 u.

전체적으로 다음과 같은 195 바이트 솔루션이 생성됩니다.

val()=hd[(fn s=>let val t=s^"\""^String.toString s^"\")"val(195,u)=(size t,t)in print u end)"val()=hd[(fn s=>let val t=s^\"\\\"\"^String.toString s^\"\\\")\"val(195,u)=(size t,t)in print u end)"]

같은 조작 변수 이름 이용하는 골프 트릭인가 !, $그리고 %대신 n, tu일부 흰 공간을 절약하기 위하여이 (볼 이 팁 마지막 182 바이트 버전 리드).

설명에 명시 적으로 언급되지 않은 다른 모든 하위 문자열 제거는 구문 또는 유형 오류를 발생시킵니다.

편집 1 : length(explode t) 그냥 size t입니다.
편집 2 : 다른 quine 접근법과 "취약점"을 지적한 Anders Kaseorg에게 감사드립니다.


"\""직접 작성 하고 String.toString이스케이프에 사용하여 -2 바이트
Anders Kaseorg

잠깐, 이것은 끔찍하다 : MLton은 "빈 출력 ( TIO )을 생성 하는 프로그램을 받아들이는 것 같습니다 .
Anders Kaseorg

@AndersKaseorg Huh, 이상합니다. 그러나 다른를 사용하여이 문제를 해결할 수 있어야합니다 let ... in ... end.
Laikoni

@AndersKaseorg 새로운 "취약점"을 도입하지 않고 문제를 해결했습니다.
Laikoni

실제로 나는 MLton을 "프로그램으로 받아들이 는 것을 보았고 , 이 커밋 에서 버그가 수정 된 것 같습니다 . 따라서 릴리스되지 않은 MLit MLit 버전을 지정하는 한 182 또는 180은 괜찮습니다.
Anders Kaseorg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.