편집 : 당신 중 일부는 의심, 공식 통역사에 버그가 있었다 : 구성 순서 .
가 반대로했다. 나는 두 가지 버전의 통역사가 있었고 여기에서 잘못된 것을 사용했습니다. 이 잘못된 버전에 대한 예제도 작성되었습니다. 리포지토리에서 인터프리터와 아래 예제를 수정했습니다. 에 대한 설명 >
도 약간 모호했기 때문에 수정했습니다. 또한 너무 오래 걸리는 것에 대한 사과는 실생활에 사로 잡혔습니다.
EDIT2 : 통역사에게 구현에 버그가 있었는데 .
그 예에 반영되었습니다 (정의되지 않은 행동에 의존했습니다). 이제 문제가 해결되었습니다.
소개
Shift 는 몇 년 전에 만든 난해한 기능 프로그래밍 언어이지만 오늘 출판되었습니다. 스택 기반이지만 Haskell과 같은 자동 카레가 있습니다.
사양
Shift에는 두 가지 데이터 유형이 있습니다.
- 임의의 양수가 함수, 인수에 대응 (입력의 수), 및 출력의리스트를 반환한다. 예를 들어, 유일한 입력을 복제하는 함수에는 arity 1이 있고 두 입력을 바꾸는 함수에는 arity 2가 있습니다.
- 공백은 모두 동일하며 기능이 아닌 것 외에 다른 목적이 없습니다.
Shift 프로그램은 0 개 이상의 명령으로 구성되며 각 명령 은 단일 ASCII 문자입니다. 총 8 개의 명령이 있습니다.
!
( apply ) 는 스택에서 함수f
와 값x
을 팝 하고에 적용f
됩니다x
.f
arity 1이 있으면f(x)
스택의 맨 앞에 목록 이 추가됩니다. arityn > 1
가있는 경우 새로운 2(n-1)
진 함수g
가 스택으로 푸시됩니다. 입력을 받아 리턴합니다 .x1,x2,...,xn-1
f(x,x1,x2,...,xn-1)
?
( blank )는 블랭크를 스택에 밀어 넣습니다.+
( clone )은 입력을 복제하는 단항 함수를 스택에 푸시합니다. 모든 값x
이에 매핑됩니다[x,x]
.>
( shift )는n
-ary 함수를 취하는 단항 함수를 스택에 푸시 하고 첫 번째 인수를 무시하고 나머지 인수 를 호출 하며 결과 앞에 붙는 1 진 함수 를f
반환합니다 . 예를 들어, 입력을 가져 와서 반환 하는 이진 함수입니다 .(n+1)
g
x
f
x
shift(clone)
a,b
[a,b,b]
/
( fork )는 세 개의 입력을 취하는 삼항 함수를 스택에 푸시 하고 공백 인 경우a,b,c
리턴 하고 그렇지 않은[b]
경우 리턴 합니다 .a
[c]
$
( call )은 함수f
와 값 을 표시하는 이진 함수를 스택에 푸시 하고 정확하게x
적용됩니다 .f
x
!
.
( 체인 ) 스택을 팝 두 기능하는 이진 함수 푸시f
및g
기능 : 및 그들의 조성물 반환h
같은 인수에 대응을 보유f
하고, 일반적으로 그 입력을 얻어 적용되는f
그들하고 완전히 적용g
(호출 결과에f
결과에서 남은 결과물에서 사용되지 않은 항목 이 포함 된 경우)h
. 예를 들어, 즉 가정f
의 두 번째 인수를 클론, 이진 함수g
입니다 전화 . 스택에 포함되어[f,g,a,b,c]
있고 포함되어 있으면.!!
포함됩니다[chain(f,g),a,b,c]
. 우리가 할 경우!!
, 다음, 다음f
첫번째에 적용되는a,b
생산,[a,b,b]
그런 다음g
arity가 2이기 때문에 생산의 첫 번째 두 요소에 적용되며[a(b),b]
스택은 마침내됩니다[a(b),b,c]
.@
( say )는 단순히 입력을 반환하는 단항 함수를 푸시하고0
공백 이거나 함수 인 경우 인쇄1
합니다.
!
단순히 값을 스택으로 푸시하는 것을 제외한 모든 명령 은 입력을 수행 할 수있는 방법이 없으며 출력하는 유일한 방법은을 사용하는 것 @
입니다. 프로그램은 명령을 하나씩 평가하고 "say"가 호출 될 때마다 0
s 또는 1
s를 인쇄 하고 종료 하여 해석됩니다 . 여기에 설명되지 않은 동작 (공백 적용, 길이가 0 또는 1 인 스택 적용, 빈에서 "체인"호출 등)은 정의되지 않습니다. 인터프리터가 충돌하거나, 자동으로 실패하거나, 입력을 요청하는 등의 작업이 수행 될 수 있습니다.
작업
당신의 임무는 Shift에 대한 통역을 작성하는 것입니다. STDIN, 명령 행 또는 함수 인수에서 해석 할 Shift 프로그램을 가져 와서 STDOUT으로 인쇄하거나 0
s 및 1
s 의 결과 (무한) 출력을 리턴해야합니다 . 함수를 작성하면 어떤 식 으로든 무한 길이 출력에 액세스 할 수 있어야합니다 (Python의 생성기, Haskell의 지연 목록 등). 또는 다른 입력 인 숫자를 가져 와서 보다 긴 경우 출력의 문자를 n
리턴 할 수 있습니다 .n
n
가장 낮은 바이트 수가 이기고 표준 허점이 허용되지 않습니다.
테스트 사례
이 Shift 프로그램은 01
다음을 인쇄합니다 .
?@!@@!
왼쪽에서 시작 : 밀어 빈, 푸시 말은 다음에 적용 말을 빈에. 이 출력 0
됩니다. 그런 다음 두 번 말하고 두 번째 말 을 첫 번째 말 에 적용하십시오 . 이 출력 1
됩니다.
이 프로그램은 영원히 반복되므로 출력이 없습니다.
$+.!!+!!
푸시 전화 와 클론은 , 다음 적용 체인 (우리가이 필요한 그들에게를 !
이후의를 체인 진 기능입니다). 이제 스택에는 하나의 인수를 가져 와서 복제하고 두 번째에서 첫 번째 사본을 호출하는 함수가 포함됩니다. 을 사용 +!!
하여이 함수를 복제하고 자체적으로 호출합니다.
이 프로그램은 0010
다음을 인쇄합니다 .
?@$.++>!.!!.!!.!!!!+?/!!!@!@>!!!
빈칸을 밀고 라고 말합니다 . 그런 다음 두 번째 인수를 복사하는 이진 함수를 작성한 b
다음 첫 번째 인수 를 복사하여 a
자체 로 작성한 다음 컴포지션을의 사본에 적용하여를 b
리턴 [a(a(b)),b]
합니다. 이에 적용 말을 빈 후 적용 말을 스택에 남아있는 두 가지 요소에.
이 프로그램은 인쇄합니다 0
. !!!
추가 한 각각 에 대해 추가를 인쇄합니다 0
.
?@+$>!>!+>!///!!>!>!.!!.!!.!!+!!!!
빈칸을 밀고 라고 말합니다 . 그런 다음 f,g,x
입력으로 사용하고를 반환 하는 삼항 함수를 작성하십시오 [f,f,g,g(x)]
. 복제 기능 자체에 적용, 그 말 과 빈. 이 애플리케이션은 스택을 변경하지 않으므로 원하는만큼 함수를 다시 적용 할 수 있습니다.
이 프로그램 001011011101111...
은 1
s 의 수가 항상 1 씩 증가 하는 무한 시퀀스를 인쇄합니다 .
@?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!!
저장소에는 주석이 달린 버전이 있습니다.
f(x1, x2, ..., xn)
하고 g(y1, y2, ..., ym)
. 호출 .
하면 둘 다 팝업되고 함수를 푸시합니다 h(z1, z2, ..., zn)
. 이제 당신은 점진적으로 카레를함으로써 모든 논쟁을 먹을 수 있습니다 !
. 후 n
응용 프로그램, 나머지 기능은 하나 개의 인자를 가지고 있었고, 그 시점에서 그것은 계산 f(z1, z2, ..., zn)
(즉, f
새로운 값을 밀어 후 즉시 소비, 당신이 카레 모든 인수에 적용) m
스택의 값과 통화를 g
그들.
.
은 값 f
보다 작은 목록을 반환 m
하면 결과가 정의되지 않습니다 (구성에 arity n
가 있으므로 스택에서 더 많은 인수를 사용할 수 없음)를 제외하고는 Martin이 설명한대로 정확하게 작동합니다 . 기본적으로의 출력은 f
임시 스택으로 사용되며, 여기서는를 사용하여 g
푸시 및 적용 되고 그 결과는 기본 스택에 추가됩니다. m
!