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àmfvà một giá trịxtừ ngăn xếp và áp dụngfchox. Nếufcó 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-1f(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-aryfvà trả về một(n+1)hàm -arygmà bỏ qua đối số đầu tiên của nóx, gọifcác hàm còn lại và xử lýxtrước kết quả. Ví dụ,shift(clone)là một hàm nhị phân nhận đầu vàoa,bvà 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,cvà trả về[b]nếualà 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àmfvà một giá trịx, và áp dụngfchoxchí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àmfvàgtrả về thành phần của chúng: một hàmhcó 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ụngfcho chúng, và sau đó áp dụng hoàn toàngcho 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 rafcòn lại trong kết quả củah. Ví dụ, giả sử đóflà một hàm nhị phân nhân bản đối số thứ hai của nó vàglà 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ìflầ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à in0nếu nó là một khoảng trống và1nế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 0s hoặc 1s 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 0s và 1s. 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ố nvà trả lại ít nhất các nký 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 avà 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ố 1s 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 ncá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 mcác giá trị từ ngăn xếp và gọi gchúng.
.hoạt động chính xác như Martin mô tả, ngoại trừ việc nếu ftrả về một danh sách nhỏ hơn mcá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 mthời gian sử dụng !, và kết quả của nó được thêm vào ngăn xếp chính.