EDIT: Như một số bạn nghi ngờ, có một lỗi trong trình thông dịch chính thức: thứ tự sáng tác .
đã bị đảo ngược. Tôi đã có hai phiên bản của trình thông dịch, và đã sử dụng sai phiên bản ở đây. Các ví dụ cũng được viết cho phiên bản không chính xác này. Tôi đã sửa trình thông dịch trong kho lưu trữ và các ví dụ bên dưới. Mô tả về >
nó cũng hơi mơ hồ, vì vậy tôi đã sửa nó. Ngoài ra, lời xin lỗi cho việc này mất quá nhiều thời gian, tôi đã bị cuốn vào một số thứ thực tế trong cuộc sống.
EDIT2: Trình thông dịch của tôi có một lỗi trong việc triển khai .
được phản ánh trong các ví dụ (họ dựa vào hành vi không xác định). Vấn đề hiện đã được khắc phục.
Giới thiệu
Shift là một ngôn ngữ lập trình chức năng bí truyền mà tôi đã tạo ra vài năm trước, nhưng được xuất bản ngày hôm nay. Nó dựa trên stack, nhưng cũng có tính năng currying tự động như Haskell.
Sự chỉ rõ
Có hai kiểu dữ liệu trong Shift:
- Chức năng, trong đó có một dương tùy ý arity (số đầu vào), và đó trả về một danh sách các kết quả đầu ra. Ví dụ, một chức năng sao chép đầu vào duy nhất của nó có arity 1 và một chức năng hoán đổi hai đầu vào của nó có arity 2.
- Các khoảng trống, tất cả đều giống hệt nhau và không có mục đích nào khác ngoài việc không phải là các chức năng.
Một chương trình Shift bao gồm 0 hoặc nhiều lệnh , mỗi lệnh là một ký tự ASCII. Tổng cộng có 8 lệnh:
!
( áp dụng ) bật một hàmf
và một giá trịx
từ ngăn xếp và áp dụngf
chox
. Nếuf
có arity 1, danh sáchf(x)
được thêm vào phía trước ngăn xếp. Nếu nó có arityn > 1
, một(n-1)
hàm -ary mớig
được đẩy lên ngăn xếp. Nó có đầu vào và trả lại .x1,x2,...,xn-1
f(x,x1,x2,...,xn-1)
?
( trống ) đẩy một khoảng trống vào ngăn xếp.+
( clone ) đẩy vào ngăn xếp một hàm unary trùng lặp đầu vào của nó: bất kỳ giá trị nàox
được ánh xạ tới[x,x]
.>
( shift ) đẩy vào ngăn xếp một hàm unary có chức năngn
-aryf
và trả về một(n+1)
hàm -aryg
mà bỏ qua đối số đầu tiên của nóx
, gọif
các hàm còn lại và xử lýx
trước kết quả. Ví dụ,shift(clone)
là một hàm nhị phân nhận đầu vàoa,b
và trả về[a,b,b]
./
( ngã ba ) đẩy vào ngăn xếp một hàm ternary có ba đầu vàoa,b,c
và trả về[b]
nếua
là một khoảng trống, và[c]
nếu không.$
( cuộc gọi ) đẩy vào ngăn xếp một hàm nhị phân bật ra một hàmf
và một giá trịx
, và áp dụngf
chox
chính xác như!
vậy..
( chuỗi ) đẩy vào ngăn xếp một hàm nhị phân bật ra hai hàmf
vàg
trả về thành phần của chúng: một hàmh
có cùng mức vớif
, và lấy đầu vào của nó một cách bình thường, áp dụngf
cho chúng, và sau đó áp dụng hoàn toàng
cho kết quả (gọi nó nhiều lần như arity của nó ra lệnh), với các mục không được sử dụng từ đầu raf
còn lại trong kết quả củah
. Ví dụ, giả sử đóf
là một hàm nhị phân nhân bản đối số thứ hai của nó vàg
là cuộc gọi . Nếu ngăn xếp chứa[f,g,a,b,c]
và chúng ta làm.!!
, thì nó chứa[chain(f,g),a,b,c]
; Nếu chúng ta làm!!
tiếp theo, thìf
lần đầu tiên được áp dụnga,b
, sản xuất[a,b,b]
, sau đóg
được áp dụng cho hai yếu tố đầu tiên vì tính chất của nó là 2, tạo ra[a(b),b]
và ngăn xếp cuối cùng sẽ là[a(b),b,c]
.@
( nói ) đẩy một hàm unary đơn giản trả về đầu vào của nó và in0
nếu nó là một khoảng trống và1
nếu đó là một hàm.
Lưu ý rằng tất cả các lệnh ngoại trừ !
chỉ đơn giản là đẩy một giá trị vào ngăn xếp, không có cách nào để thực hiện đầu vào và cách duy nhất để xuất bất cứ thứ gì là sử dụng @
. Một chương trình được diễn giải bằng cách đánh giá từng lệnh một, in 0
s hoặc 1
s bất cứ khi nào "say" được gọi và thoát. Bất kỳ hành vi nào không được mô tả ở đây (áp dụng khoảng trống, áp dụng một ngăn xếp có độ dài 0 hoặc 1, gọi "chuỗi" trên một khoảng trống, v.v.) là không xác định: trình thông dịch có thể bị sập, thất bại âm thầm, yêu cầu nhập liệu hoặc bất cứ điều gì.
Nhiệm vụ
Nhiệm vụ của bạn là viết một trình thông dịch cho Shift. Nó sẽ lấy từ STDIN, dòng lệnh hoặc đối số chức năng một chương trình Shift sẽ được diễn giải và in ra STDOUT hoặc trả về kết quả đầu ra (có thể là vô hạn) của 0
s và 1
s. Nếu bạn viết một hàm, bạn phải có khả năng truy cập các đầu ra có độ dài vô hạn theo một cách nào đó (trình tạo trong Python, danh sách lười biếng trong Haskell, v.v.). Ngoài ra, bạn có thể lấy một đầu vào khác, một số n
và trả lại ít nhất các n
ký tự của đầu ra nếu nó dài hơn n
.
Số byte thấp nhất sẽ thắng và các sơ hở tiêu chuẩn không được phép.
Các trường hợp thử nghiệm
Chương trình Shift này in 01
:
?@!@@!
Bắt đầu từ bên trái: đẩy một khoảng trống, đẩy nói , sau đó áp dụng nói vào chỗ trống. Kết quả này 0
. Sau đó, đẩy nói hai lần, và áp dụng lần nói thứ hai cho lần đầu tiên. Kết quả này 1
.
Chương trình này lặp lại mãi mãi, không tạo ra đầu ra:
$+.!!+!!
Đẩy cuộc gọi và sao chép , sau đó áp dụng chuỗi cho chúng (chúng ta cần hai !
s vì chuỗi là hàm nhị phân). Bây giờ ngăn xếp chứa một hàm lấy một đối số, sao chép nó và gọi bản sao đầu tiên trên thứ hai. Với +!!
, chúng tôi nhân đôi chức năng này và gọi nó trên chính nó.
Chương trình này in 0010
:
?@$.++>!.!!.!!.!!!!+?/!!!@!@>!!!
Đẩy một cái trống và nói . Sau đó, soạn một hàm nhị phân sao chép đối số thứ hai của nó b
, sau đó sao chép hàm thứ nhất a
và tự kết hợp nó với chính nó, sau đó áp dụng thành phần cho bản sao của b
, trả về [a(a(b)),b]
. Áp dụng nó để nói và để trống, sau đó áp dụng nói cho hai yếu tố còn lại trên ngăn xếp.
Chương trình này in 0
. Đối với mỗi !!!
cái mà bạn gắn vào nó, nó sẽ in thêm 0
.
?@+$>!>!+>!///!!>!>!.!!.!!.!!+!!!!
Đẩy một cái trống và nói . Sau đó, soạn một hàm ternary lấy f,g,x
đầu vào và trả về [f,f,g,g(x)]
. Nhân bản chức năng đó, và áp dụng nó cho chính nó, nói và trống. Ứng dụng này không thay đổi ngăn xếp, vì vậy chúng ta có thể áp dụng lại chức năng nhiều lần như chúng ta muốn.
Chương trình này in chuỗi vô hạn 001011011101111...
, trong đó số 1
s luôn tăng thêm một:
@?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!!
Các kho chứa một phiên bản chú thích.
f(x1, x2, ..., xn)
và g(y1, y2, ..., ym)
. Gọi .
bật cả hai và đẩy một chức năng h(z1, z2, ..., zn)
. Bây giờ bạn có thể ăn hết những lý lẽ đó bằng cách dần dần chế biến nó !
. Sau n
các ứng dụng như vậy, hàm còn lại chỉ có một đối số và tại thời điểm đó, nó sẽ tính toán f(z1, z2, ..., zn)
(nghĩa là f
áp dụng cho tất cả các đối số mà bạn đã sử dụng), đẩy một số giá trị mới, sau đó sử dụng ngay m
các giá trị từ ngăn xếp và gọi g
chúng.
.
hoạt động chính xác như Martin mô tả, ngoại trừ việc nếu f
trả về một danh sách nhỏ hơn m
các giá trị, kết quả không được xác định (chế phẩm có arity n
, vì vậy nó không thể ăn thêm đối số từ ngăn xếp). Về cơ bản, đầu ra của f
được sử dụng như một ngăn xếp tạm thời, trên đó g
được đẩy và áp dụng m
thời gian sử dụng !
, và kết quả của nó được thêm vào ngăn xếp chính.