Husk adalah bahasa golf yang cukup baru, dibuat oleh pengguna PPCG Leo dan Zgarb . Itu sudah mulai semakin kompetitif, sering tetap dekat atau bahkan mengalahkan bahasa yang dikenal sangat singkat, seperti Jelly dan 05AB1E.
Mari kita daftar beberapa teknik golf yang agak spesifik untuk Husk. Seperti biasa, silakan kirim satu tip per jawaban.
Jawaban:
Gunakan nilai balik dari predikat
Dalam Husk, fungsi yang menguji input mereka untuk beberapa properti biasanya akan mengembalikan hasil yang berarti dalam kasus kebenaran, karena setiap bilangan bulat positif adalah benar.
Contoh:
¹ perbedaan yang tepat berarti perbedaan poin kode untuk karakter. Ini juga merujuk pada urutan argumen. yaitu Untuk
<x y
, akanx-y
sumber
Gunakan label garis yang meluap
Seperti yang mungkin sudah Anda ketahui,
[₀-₉]+|[₀-₉]
adalah regex untuk sintaks untuk memanggil saluran yang berbeda dari yang Anda gunakan saat ini.Tip ini sangat berguna jika Anda ingin fungsi yang didefinisikan pada baris tertentu disebut sebagai argumen lebih dari satu fungsi dalam tabel di bawah ini, atau sebagai argumen untuk satu atau lebih fungsi di bawah ini dan dengan sendirinya.
Tabel fungsi:
Baris dalam kode Anda diberi label dengan indeks berbasis 0 masing-masing, dari atas ke bawah. Jika M <N , di mana M adalah label dan N adalah jumlah baris dalam kode Anda, label hanya merupakan fungsi yang didefinisikan pada baris M . Jika N ≤ M <N * 6 , itu mewakili fungsi dari tabel di atas pada indeks ⌊M ÷ N⌋ dengan fungsi yang didefinisikan pada baris M mod N sebagai argumen pertama. Jika N * 6 ≤ M , kesalahan indeks dinaikkan.
sumber
Lambdas bisa lebih pendek dari fungsi baru
Seperti yang mungkin Anda ketahui jika Anda memiliki program multi-baris, Anda dapat merujuk ke baris dengan subskrip
₀…₉
, misalnya dalam kasus₁
akan merujuk ke fungsig
. Sekarang jika Anda selalu menerapkan input ke fungsig
(dan menggunakannya beberapa kali); sesuatu seperti ini:Anda harus memperkenalkan lambda karena menghemat 1 byte untuk setiap penggunaan tambahan:
Kebalikannya mungkin benar juga
Dalam kasus lambda referensial diri (
φχψ
), ada kasus khusus di mana Anda menerapkan input langsung ke fungsi rekursif, dalam kasus ini Anda lebih baik menggunakan subskrip₀
daripada menentukan lambda baru dan menggunakan⁰
.sumber
Penggunaan
Γ
Penggunaan utama built-in
Γ
, yang dikenal sebagai pencocokan pola pada daftar atau dekonstruksi daftar , adalah untuk membagi daftar menjadi kepala dan ekor, dan menerapkan fungsi biner pada daftar tersebut. Ini sesuai dengan idiom pencocokan pola Haskelldi mana
<something>
ekspresi berisix
,xs
dan mungkinf
. Ada 4 kelebihanΓ
, masing-masing bekerja sedikit berbeda.list
Overloading pertama
list
,, mengambil nilaia
dan fungsi binerf
. Ini mengembalikan fungsi baru yang mengambil daftar, kembalia
jika kosong, dan memanggilf
kepala dan ekor jika itu kosong. Misalnya,Γ_1€
ambil daftar, kembali-1
jika kosong, dan indeks kemunculan pertama elemen pertama di ekor jika tidak.listN
Overloading kedua,
listN
mirip denganlist
, kecuali yanga
dihilangkan dan nilai default dari tipe pengembalian digunakan sebagai gantinya. Misalnya,Γ€
setara denganΓ0€
, karena nilai numerik default adalah0
.Dalam praktiknya,
listN
digunakan lebih sering daripadalist
, karena nilai default tidak relevan atau persis apa yang Anda butuhkan. Pola umum adalahΓ~αβγ
, di manaαβγ
ada tiga fungsi; ini berlakuβ
untuk elemen pertama danγ
ke ekor, dan menggabungkan hasilnya denganα
. Itu digunakan misalnya dalam jawaban ini . Pola lain termasuk hanyaΓo:α
menerapkanα
ke elemen pertama, danΓ·:mα
untuk menerapkanα
ke semua elemen kecuali yang pertama. Yang terakhir digunakan dalam jawaban ini .listF
Overloading ketiga sedikit lebih terlibat. Seperti
list
, dibutuhkan nilaia
dan fungsif
, dan mengembalikan fungsi barug
yang mengambil daftar. Namun, kali inif
mengambil argumen fungsi tambahan, yang merupakang
dirinya sendiri, dan dapat menyebutnya pada nilai apa pun (termasuk, namun tidak terbatas pada, ujung daftar input). Ini berartilistF
menerapkan skema rekursi umum pada daftar.listF
tidak sering digunakan, karena rekursi eksplisit denganlist
/listN
biasanya memiliki panjang yang sama atau lebih pendek, seperti pada jawaban ini .listNF
listNF
adalah untuklistF
apalistN
adalahlist
: inputa
dihilangkan, dan nilai default dari tipe pengembalian digunakan sebagai gantinya. Dalam keadaan yang jarang terjadi, bisa lebih pendek dari lipatan kanan, misalnya dalam jawaban ini .Sebagai contoh versi rekursif
Γ
, fungsiΓλ·:o⁰↔
mengocok daftar dalam urutan pertama, terakhir, kedua, kedua-ke-terakhir, ketiga, ketiga-ke-terakhir, dan seterusnya. Cobalah online! Fungsinyaf
adalah lambda eksplisitλ·:o⁰↔
, yang argumennya⁰
adalah seluruh fungsi. Yangf
dilakukan adalah membalikkan ekor↔
, lalu memanggil fungsi utama secara rekursifo⁰
, dan akhirnya menempelkan kepala kembali·:
. Tentu saja,Γ·:o₀↔
satu byte lebih pendek, tetapi tidak berfungsi jika garis berisi sesuatu selain fungsi ini.sumber
Combinator dapat diterapkan ke fungsi-fungsi tingkat tinggi
Misalkan Anda memiliki daftar bilangan bulat X , dan Anda ingin menghitung jumlah elemen X yang lebih besar dari panjang (X) . Elemen penghitungan yang memenuhi predikat dilakukan dengan fungsi yang lebih tinggi
#
, tapi di sini predikat (menjadi lebih besar dari panjang (X) ) tergantung pada X . Solusinya adalah menerapkan kombinatorṠ
ke#
dan fungsio>L
yang memeriksa apakah daftar lebih pendek dari angka. Dalam fungsiṠ#o>L
, daftar X diteruskan keo>L
, fungsi yang diterapkan sebagian diteruskan ke#
, dan X diberikan#
sebagai argumen kedua.Secara umum, jika
α
adalah fungsi tingkat tinggi,β
fungsi biner danγ
fungsi unary,Ṡαβ
setara dengan pseudocode Haskell§αβγ
setara dengandan
~αβγ
setara denganselama jenisnya cocok.
Sebagai contoh konkret lainnya,
§►δṁ≠P
temukan permutasi daftar X yang memaksimalkan jumlah perbedaan absolut ke nilai-nilai X yang sesuai (δṁ≠
ritsleting dua daftar menggunakan perbedaan absolut dan mengambil jumlah).sumber
Nilai default Husk
Sekam tidak seketat Haskell di mana Anda mengalami masalah ketika misalnya Anda mencoba untuk mendapatkan
last
elemen daftar kosong. Untuk mencapai ini, ia menggunakan nilai yang telah ditentukan, berikut adalah daftar nilai default, maksimum dan minimum:* Di sini ∞ harus menunjukkan daftar maksimum tak terbatas yang sesuai (lihat contoh di bawah ini)
Catatan: Untuk tupel (X, Y) akan menggunakan nilai untuk setiap komponen secara terpisah.
Kapan mereka digunakan
Sementara maxima dan minima hanya digunakan untuk
▲▼
pada daftar kosong (misalnyahusk -u "▼" "[]:LLN"
akan mengembalikan daftar tak terhinggaInf
) nilai default digunakan di beberapa tempat:F
danḞ
)Θ
)r
) gagal←→
) atau mengindeks menjadi satu (!
)Γ
) pada daftar kosong►
atau◄
pada daftar kosongsumber