표준 ML , 182176 바이트
";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
인용 되지 않은 버전 : 코딩 그라운드에서 사용해보십시오.
인용 버전 : 코딩 그라운드에서 사용해보십시오.
출력은 다음과 같습니다.
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
코드는 선언에 의한 선언으로 해석되고 (각각 ;
선언이 종료 됨) 각 선언의 값과 유형을 보여줍니다.
배경
SML에는 다음과 같은 형식이 있습니다 <code>"<code in quotes>"
.
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
그리고 하나의 형태 "<code in quotes>"<code>
:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
둘 다 사실에 의존 <code>
-part에 따옴표가 포함되어 있지 않기 때문에 이스케이프 할 필요없이 인용 할 수 있으며 "
quine을 출력하는 데 필요한 값은 str(chr 34)
입니다.
또한 암시 적 식별자에 크게 의존합니다. it
선언에 명시 적 식별자가 제공되지 않을 때 사용되는 .
제 quine에서의 str(chr 34);
귀속 it
함유 문자열 "
, fn x=>
익명의 기능이 하나 개의 인자를 복용 시작 x
후, 연접을 x^it^x^it
결과 스트링을 출력한다. 이 익명 함수는 프로그램 코드가 포함 된 문자열에 직접 적용되므로 연결x^it^x^it
생성 <code>"<code>"
됩니다.
두 번째 quine ";str(chr 34)^it;print(it^it)";
은에 바인딩 된 문자열로 프로그램 코드로 시작 합니다 it
. 그런 다음 str(chr 34)^it;
따옴표를 문자열의 시작 부분에 연결하고 명시적인 식별자가 주어지지 않으면 결과 문자열 "<code>
이에 바인딩됩니다 it
. 마지막으로 print(it^it)
문자열 자체와 연결하여 "<code>"<code>
인쇄합니다.
설명
편집 : 더 이상 108 바이트 버전으로 업데이트되지 않지만이 설명을 읽은 후에도 이해할 수 있습니다.
따옴표로 안전한 quine은 위의 두 가지 접근 방식을 결합하며 그 자체는 형식 "<code>"<code>
입니다. 이것을 다시 따옴표로 묶으면 yields ""<code>"<code>"
이므로 빈 문자열을 얻은 다음 다른 형식의 quine을 얻습니다.
즉, 프로그램은 "<code>
identifier 형식 으로 자체 소스를 제공 it
받거나 it
단지 "
자체 소스 <code>
를 인수로 제공하므로 이러한 인수를 처리하는 함수 여야합니다.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
우리가이 경우에 식별하기 위해, 우리는의 크기가 있는지 여부를 확인 it
후 1보다 큰 경우에는없는 it
것입니다 "
그리고 우리는 두 번째 경우에 너무 else
part의 반환 익명 함수 fn x=>print(it^it^x^it^x^it)
의 문자열로 소스 뒤에 있기 때문에 다음이라고합니다 . it^it^
프로그램 시작시 빈 문자열에 필요한 행간 을 주목하십시오 .
경우 size it
우리는에 1보다 큰 then
part의 바로 수행 print(it^it)
, 오른쪽? SML이 강력하게 형식화되었다는 것을 말하지 않았기 때문에 조건부 if <cond> then <exp_1> else <exp_2>
에는 항상 동일한 유형이 있어야하며 이는 표현식 <exp_1>
과 유형이 같아야 함을 의미합니다 <exp_2>
. 우리는 이미 그 else
부분 의 유형을 알고 있습니다 : 문자열을 취해서 호출하는 익명 함수 print
는 type string -> <return type of print>
을 print
가지고, type string -> unit
( 다른 언어 unit
와 비슷합니다 void
)을 가지므로 결과 타입은 다시 string -> unit
입니다.
따라서 then
부분 print(it^it)
이 type unit
인 경우 유형 불일치 오류가 발생합니다. 그럼 fn _=>print(it^it)
어때요? ( _
그 자체로이 익명 함수 타입했다 사용하지 않는 인자에 대한 와일드 카드이다) 그래서 강제 우리의 조건과 관련하여, 임의의 유형의 약자를 이 작동 할 유형입니다. (type 변수 는 type으로 인스턴스화됩니다 .) 그러나이 경우 익명 함수가 호출되지 않으므로 아무것도 인쇄하지 않습니다! -part에 들어가면 전체 코드는'a -> unit
'a
string -> unit
'a
string
then
"<code>"<code>
-이므로 <code>
-part는 함수로 평가되지만 그 뒤에 아무것도 나오지 않으므로 호출되지 않습니다.
대신 우리는 양식이있는 sequentialisation 사용 하는 임의의 유형과 유형이있을 수 있습니다 전체 sequentialisation의 유형을 제공합니다. 기능적인 관점에서 to 의 값 은 단순히 무시되지만 SML은 명령형 구문도 지원하므로 표현식에 부작용이있을 수 있습니다. 즉, 우리 는 -part 로 간주하여 먼저 인쇄 한 다음 올바른 유형 의 함수를 반환합니다 .(<exp_1>; ...; <exp_n>)
<exp_1>
<exp_n-1>
<exp_n>
<exp_1>
<exp_n-1>
(print(it^it);print)
then
print