Tips untuk bermain golf di Husk

15

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.

Tuan Xcoder
sumber
1
@totallyhuman pertama Sekam jawaban Masih belum yang baru
H.PWiz

Jawaban:

10

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:

≠  Numbers: Absolute difference
   Chars:   Absolute difference of code points
   Lists:   First Index where the differ

Comparisons <, >, ≤, ≥:

For strict comparisons:
Numbers,Chars:  max 0 (the appropriate difference¹)
Lists: The first index where the comparison between the two lists is true

For non-strict comparisons:
Numbers,Chars: max 0 (the appropriate difference + 1)
Lists: Either the result of the strict comparison or, if they are equal,
       the length of the list + 1

ṗ  Index into the list of prime numbers

V  The index of the first element for which the condition is true

€  The first index of that element/substring in the list

£  Works like €

&  Given two arguments of the same type will return the second argument if false,
   otherwise will return the first argument

|  Given two arguments of the same type will return the second argument if true,
   otherwise will return the first argument

¦  Return the quotient if divisibility holds

Λ,E,Ë  Will all return length+1 in truthy cases

Char predicates:
□,±,√,D,½  will each return the codepoint of its argument on truthy cases

¹ perbedaan yang tepat berarti perbedaan poin kode untuk karakter. Ini juga merujuk pada urutan argumen. yaitu Untuk <x y, akanx-y

H.Piz
sumber
7

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:

+----------+----------+
|Index     |Function  |
+----------+----------+
|1         |´ (argdup)|
+----------+----------+
|2         |` (flip)  |
+----------+----------+
|3         |m (map)   |
+----------+----------+
|4         |z (zip)   |
+----------+----------+
|5         |S (hook)  |
+----------+----------+

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.

Erik the Outgolfer
sumber
5

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

f
g

akan merujuk ke fungsi g. Sekarang jika Anda selalu menerapkan input ke fungsi g(dan menggunakannya beberapa kali); sesuatu seperti ini:

f₁⁰[...]g₁⁰[...]
h

Anda harus memperkenalkan lambda karena menghemat 1 byte untuk setiap penggunaan tambahan:

λf⁰[...]g⁰[...])h

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
5

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 Haskell

f (x : xs) = <something>
f [] = <something else>

di mana <something>ekspresi berisi x, xsdan mungkin f. Ada 4 kelebihan Γ, masing-masing bekerja sedikit berbeda.

list

Overloading pertama list,, mengambil nilai adan fungsi biner f. Ini mengembalikan fungsi baru yang mengambil daftar, kembali ajika kosong, dan memanggil fkepala dan ekor jika itu kosong. Misalnya, Γ_1€ambil daftar, kembali -1jika kosong, dan indeks kemunculan pertama elemen pertama di ekor jika tidak.

listN

Overloading kedua, listNmirip dengan list, kecuali yang adihilangkan dan nilai default dari tipe pengembalian digunakan sebagai gantinya. Misalnya, Γ€setara dengan Γ0€, karena nilai numerik default adalah 0.

Dalam praktiknya, listNdigunakan lebih sering daripada list, 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 nilai adan fungsi f, dan mengembalikan fungsi baru gyang mengambil daftar. Namun, kali ini fmengambil argumen fungsi tambahan, yang merupakan gdirinya sendiri, dan dapat menyebutnya pada nilai apa pun (termasuk, namun tidak terbatas pada, ujung daftar input). Ini berarti listFmenerapkan skema rekursi umum pada daftar. listFtidak sering digunakan, karena rekursi eksplisit dengan list/ listNbiasanya memiliki panjang yang sama atau lebih pendek, seperti pada jawaban ini .

listNF

listNFadalah untuk listFapa listNadalah list: input adihilangkan, 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! Fungsinya fadalah lambda eksplisit λ·:o⁰↔, yang argumennya adalah seluruh fungsi. Yang fdilakukan adalah membalikkan ekor , lalu memanggil fungsi utama secara rekursif o⁰, dan akhirnya menempelkan kepala kembali ·:. Tentu saja, Γ·:o₀↔satu byte lebih pendek, tetapi tidak berfungsi jika garis berisi sesuatu selain fungsi ini.

Zgarb
sumber
3

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 fungsi o>Lyang memeriksa apakah daftar lebih pendek dari angka. Dalam fungsi Ṡ#o>L, daftar X diteruskan ke o>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

\x -> α (\y -> β x y) x

§αβγ setara dengan

\x -> α (\y -> β x y) (γ x)

dan ~αβγsetara dengan

\x y -> α (\z -> β x z) (γ y)

selama jenisnya cocok.

Sebagai contoh konkret lainnya, §►δṁ≠Ptemukan permutasi daftar X yang memaksimalkan jumlah perbedaan absolut ke nilai-nilai X yang sesuai ( δṁ≠ritsleting dua daftar menggunakan perbedaan absolut dan mengambil jumlah).

Zgarb
sumber
3

Nilai default Husk

Sekam tidak seketat Haskell di mana Anda mengalami masalah ketika misalnya Anda mencoba untuk mendapatkan lastelemen daftar kosong. Untuk mencapai ini, ia menggunakan nilai yang telah ditentukan, berikut adalah daftar nilai default, maksimum dan minimum:

.------------------------------------.---------------.----------.-------.
|   Type (X and Y are placeholders)  | default (def) |    max   |  min  |
|------------------------------------|---------------|----------|-------|
|       Character (C)                |      ' '      | \1114111 | \NUL  |
|       Numbers   (N)                |       0       |   Inf    | -Inf  |
|       List of X (LX)               |      []       |  ∞ max   |   []  | *
|       Function :: X -> Y           | const (def Y) |   n/a    |  n/a  |
'------------------------------------'---------------'----------'-------'

* 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 (misalnya husk -u "▼" "[]:LLN"akan mengembalikan daftar tak terhingga Inf) nilai default digunakan di beberapa tempat:

  • melipat daftar kosong tanpa memberikan nilai sendiri ( Fdan )
  • mengawali nilai default (dengan Θ)
  • ketika membaca ( r) gagal
  • mendapatkan elemen pertama / terakhir ( ←→) atau mengindeks menjadi satu ( !)
  • pencocokan pola ( Γ) pada daftar kosong
  • menggunakan atau pada daftar kosong
ბიმო
sumber