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 fungsifdan nilaixdari tumpukan, dan berlakufuntukx. Jikafmemiliki arity 1, daftarf(x)ditambahkan ke bagian depan tumpukan. Jika memiliki arityn > 1,(n-1)fungsi -ary barugdidorong ke stack. Dibutuhkan input dan pengembalian .x1,x2,...,xn-1f(x,x1,x2,...,xn-1)?( kosong ) mendorong yang kosong ke tumpukan.+( klon ) mendorong ke stack fungsi yang tidakxdikenal yang menggandakan inputnya: nilai apa pun dipetakan ke[x,x].>( shift ) mendorong ke stack fungsi unary yang mengambilnfungsi -aryf, dan mengembalikan(n+1)fungsi -arygyang mengabaikan argumen pertamanyax, memanggilfyang tersisa, dan mengetukxdi depan hasilnya. Misalnya,shift(clone)adalah fungsi biner yang mengambil inputa,bdan mengembalikan[a,b,b]./( fork ) mendorong ke stack fungsi terner yang mengambil tiga inputa,b,c, dan mengembalikan[b]jikaakosong, dan[c]sebaliknya.$( Panggilan ) dorongan untuk stack fungsi biner yang muncul fungsifdan nilaix, dan berlakufuntukxpersis seperti!yang dilakukannya..( rantai ) mendorong ke stack fungsi biner yang muncul dua fungsifdang, dan mengembalikan komposisi mereka: fungsihyang memiliki arity yang sama denganf, dan yang mengambil inputnya secara normal, berlakufuntuk mereka, dan kemudian sepenuhnya berlakuguntuk hasil (panggilan) sebanyak yang ditentukan arity), dengan item yang tidak digunakan dari output yangftersisa dalam hasilh. Sebagai contoh, anggap itufadalah fungsi biner yang mengkloning argumen keduanya, dangadalah panggilan . Jika tumpukan berisi[f,g,a,b,c]dan kami lakukan.!!, maka berisi[chain(f,g),a,b,c]; jika kita lakukan!!selanjutnya, makafpertama kali diterapkana,b, berproduksi[a,b,b], kemudiangditerapkan 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 mencetak0jika itu kosong, dan1jika 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 0s atau 1s 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 0s dan 1s. 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 nkarakter 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 adan 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,xinput 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 1s 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 naplikasi seperti itu, fungsi yang tersisa hanya memiliki satu argumen, dan pada saat itu ia menghitung f(z1, z2, ..., zn)(yaitu fditerapkan pada semua argumen yang Anda curry), yang mendorong beberapa nilai baru, dan kemudian segera mengkonsumsi mnilai dari stack dan memanggilnya g.
.bekerja persis seperti yang dijelaskan Martin, kecuali jika fmengembalikan daftar kurang dari mnilai, hasilnya tidak terdefinisi (komposisinya arity n, sehingga tidak dapat memakan lebih banyak argumen dari tumpukan). Pada dasarnya, output fdigunakan sebagai tumpukan sementara, yang gdidorong dan diterapkan mkali menggunakan !, dan hasilnya ditambahkan ke tumpukan utama.