EDIT: Seperti yang Anda duga, ada bug pada penerjemah resmi: urutan komposisi .
terbalik. Saya memiliki dua versi penerjemah, dan menggunakan yang salah di sini. Contoh-contoh juga ditulis untuk versi yang salah ini. Saya telah memperbaiki juru bahasa di repositori, dan contoh-contoh di bawah ini. Penjelasannya >
juga agak ambigu, jadi saya sudah memperbaikinya. Juga, permintaan maaf untuk ini sudah begitu lama, saya terjebak dalam beberapa hal kehidupan nyata.
EDIT2: Penerjemah saya memiliki bug dalam implementasi .
yang tercermin dalam contoh (mereka bergantung pada perilaku yang tidak ditentukan). Masalahnya sekarang sudah diperbaiki.
pengantar
Shift adalah bahasa pemrograman fungsional esoteris yang saya buat beberapa tahun yang lalu, tetapi diterbitkan hari ini. Ini berbasis stack, tetapi juga memiliki currying otomatis seperti Haskell.
Spesifikasi
Ada dua tipe data di Shift:
- Fungsi, yang memiliki arity positif sewenang-wenang (jumlah input), dan yang mengembalikan daftar output. Misalnya, fungsi yang menggandakan inputnya hanya memiliki arity 1, dan fungsi yang menukar kedua inputnya memiliki arity 2.
- Kosong, yang semuanya identik dan tidak memiliki tujuan selain tidak berfungsi.
Program Shift terdiri dari nol atau lebih perintah , yang masing-masing merupakan karakter ASCII tunggal. Total ada 8 perintah:
!
( berlaku ) memunculkan fungsif
dan nilaix
dari tumpukan, dan berlakuf
untukx
. Jikaf
memiliki arity 1, daftarf(x)
ditambahkan ke bagian depan tumpukan. Jika memiliki arityn > 1
,(n-1)
fungsi -ary barug
didorong ke stack. Dibutuhkan input dan pengembalian .x1,x2,...,xn-1
f(x,x1,x2,...,xn-1)
?
( kosong ) mendorong yang kosong ke tumpukan.+
( klon ) mendorong ke stack fungsi yang tidakx
dikenal yang menggandakan inputnya: nilai apa pun dipetakan ke[x,x]
.>
( shift ) mendorong ke stack fungsi unary yang mengambiln
fungsi -aryf
, dan mengembalikan(n+1)
fungsi -aryg
yang mengabaikan argumen pertamanyax
, memanggilf
yang tersisa, dan mengetukx
di depan hasilnya. Misalnya,shift(clone)
adalah fungsi biner yang mengambil inputa,b
dan mengembalikan[a,b,b]
./
( fork ) mendorong ke stack fungsi terner yang mengambil tiga inputa,b,c
, dan mengembalikan[b]
jikaa
kosong, dan[c]
sebaliknya.$
( Panggilan ) dorongan untuk stack fungsi biner yang muncul fungsif
dan nilaix
, dan berlakuf
untukx
persis seperti!
yang dilakukannya..
( rantai ) mendorong ke stack fungsi biner yang muncul dua fungsif
dang
, dan mengembalikan komposisi mereka: fungsih
yang memiliki arity yang sama denganf
, dan yang mengambil inputnya secara normal, berlakuf
untuk mereka, dan kemudian sepenuhnya berlakug
untuk hasil (panggilan) sebanyak yang ditentukan arity), dengan item yang tidak digunakan dari output yangf
tersisa dalam hasilh
. Sebagai contoh, anggap ituf
adalah fungsi biner yang mengkloning argumen keduanya, dang
adalah panggilan . Jika tumpukan berisi[f,g,a,b,c]
dan kami lakukan.!!
, maka berisi[chain(f,g),a,b,c]
; jika kita lakukan!!
selanjutnya, makaf
pertama kali diterapkana,b
, berproduksi[a,b,b]
, kemudiang
diterapkan pada dua elemen pertama itu karena aritynya adalah 2, menghasilkan[a(b),b]
, dan tumpukan akhirnya akan[a(b),b,c]
.@
( katakanlah ) mendorong fungsi unary yang hanya mengembalikan inputnya, dan mencetak0
jika itu kosong, dan1
jika itu adalah fungsi.
Perhatikan bahwa semua perintah kecuali !
hanya mendorong nilai ke tumpukan, tidak ada cara untuk melakukan input, dan satu-satunya cara untuk menghasilkan apa pun adalah dengan menggunakan @
. Suatu program ditafsirkan dengan mengevaluasi perintah satu per satu, mencetak 0
s atau 1
s setiap kali "katakan" dipanggil, dan keluar. Perilaku apa pun yang tidak diuraikan di sini (menerapkan blank, menerapkan stack dengan panjang 0 atau 1, memanggil "chain" pada blank, dll.) Tidak terdefinisi: penerjemah mungkin macet, gagal dalam diam, meminta input, atau apa pun.
Tugas
Tugas Anda adalah menulis juru bahasa untuk Shift. Ini harus mengambil dari STDIN, baris perintah, atau argumen fungsi program Shift untuk ditafsirkan, dan mencetak ke STDOUT atau mengembalikan hasil yang dihasilkan (mungkin tak terbatas) dari 0
s dan 1
s. Jika Anda menulis suatu fungsi, Anda harus dapat mengakses keluaran panjang tak terbatas dengan beberapa cara (generator dengan Python, daftar malas di Haskell, dll). Atau, Anda dapat mengambil input lain, nomor n
, dan mengembalikan setidaknya n
karakter dari output jika lebih lama dari n
.
Hitungan byte terendah menang, dan celah standar tidak diizinkan.
Uji Kasus
Program Shift ini mencetak 01
:
?@!@@!
Mulai dari kiri: dorong kosong, dorong say , lalu terapkan say ke kosong. Ini output 0
. Kemudian, mendorong mengatakan dua kali, dan menerapkan kedua mengatakan yang pertama. Ini output 1
.
Program ini berulang selamanya, tanpa menghasilkan output:
$+.!!+!!
Tekan panggilan dan klon , lalu terapkan rantai ke mereka (kita perlu dua !
s karena rantai adalah fungsi biner). Sekarang stack berisi fungsi yang mengambil satu argumen, menggandakannya, dan memanggil salinan pertama pada argumen kedua. Dengan +!!
, kami menduplikasi fungsi ini dan memanggilnya sendiri.
Program ini mencetak 0010
:
?@$.++>!.!!.!!.!!!!+?/!!!@!@>!!!
Dorong kosong dan katakan . Kemudian, buat fungsi biner yang menyalin argumen kedua b
, lalu salin yang pertama a
dan buat dengan sendirinya, lalu terapkan komposisi ke salinan b
, kembali [a(a(b)),b]
. Terapkan untuk berkata dan kosongkan, lalu terapkan katakan pada dua elemen yang tersisa di tumpukan.
Program ini mencetak 0
. Untuk setiap !!!
yang Anda tambahkan, ia mencetak tambahan 0
.
?@+$>!>!+>!///!!>!>!.!!.!!.!!+!!!!
Dorong kosong dan katakan . Kemudian, buat fungsi terner yang mengambil f,g,x
input dan pengembalian [f,f,g,g(x)]
. Kloning fungsi itu, dan terapkan pada dirinya sendiri, katakanlah , dan kosong. Aplikasi ini tidak mengubah tumpukan, jadi kita dapat menerapkan fungsi lagi sebanyak yang kita inginkan.
Program ini mencetak urutan tanpa batas 001011011101111...
, di mana jumlah 1
s selalu bertambah satu:
@?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!!
Repositori berisi versi beranotasi.
f(x1, x2, ..., xn)
dan g(y1, y2, ..., ym)
. Memanggil .
muncul keduanya dan mendorong suatu fungsi h(z1, z2, ..., zn)
. Sekarang Anda bisa makan semua argumen itu dengan secara bertahap menyentuhnya !
. Setelah n
aplikasi seperti itu, fungsi yang tersisa hanya memiliki satu argumen, dan pada saat itu ia menghitung f(z1, z2, ..., zn)
(yaitu f
diterapkan pada semua argumen yang Anda curry), yang mendorong beberapa nilai baru, dan kemudian segera mengkonsumsi m
nilai dari stack dan memanggilnya g
.
.
bekerja persis seperti yang dijelaskan Martin, kecuali jika f
mengembalikan daftar kurang dari m
nilai, hasilnya tidak terdefinisi (komposisinya arity n
, sehingga tidak dapat memakan lebih banyak argumen dari tumpukan). Pada dasarnya, output f
digunakan sebagai tumpukan sementara, yang g
didorong dan diterapkan m
kali menggunakan !
, dan hasilnya ditambahkan ke tumpukan utama.