Husk - совершенно новый язык игры в гольф, созданный пользователями PPCG Leo и Zgarb . Он начал становиться все более и более конкурентоспособным, часто оставаясь близким или даже опережая языки, известные как очень лаконичные, такие как Jelly и 05AB1E.
Давайте перечислим некоторые из техник игры в гольф, которые несколько специфичны для Husk. Как всегда, пожалуйста, оставьте один совет за ответ.
Ответы:
Используйте возвращаемое значение из предикатов
В Husk функции, которые проверяют свои входные данные для некоторого свойства, обычно возвращают значимый результат в истинных случаях, поскольку любое положительное целое число является правдивым.
Примеры:
¹ соответствующая разница означает разницу кодовых точек для символов. Это также относится к порядку аргументов. т.е.
<x y
, будетx-y
источник
Используйте переполненные метки строк
Как вы, возможно, уже знаете,
[₀-₉]+|[₀-₉]
это регулярное выражение для синтаксиса для вызова линии, отличной от той, в которой вы сейчас находитесь.Этот совет особенно полезен, если вы хотите, чтобы функция, определенная в конкретной строке, вызывалась в качестве аргумента более чем одной из функций в таблице ниже или в качестве аргумента для одной или нескольких функций ниже и сама по себе.
Таблица функций:
Строки в вашем коде помечены соответствующими 0-значными индексами сверху вниз. Если M <N , где M является этикетка и N это количество строк в коде, метка просто представляет собой функцию , определенную в строке М . Если N ≤ M <N * 6 , он представляет функцию из таблицы выше по индексу ⌊M ÷ N⌋ с функцией, определенной в строке M mod N, в качестве первого аргумента. Если N * 6 ≤ M , возникает ошибка индекса.
источник
Лямбда может быть короче новых функций
Как вы, вероятно, знаете, если у вас есть многострочная программа, вы можете ссылаться на строки с индексами
₀…₉
, например, в случае₁
будет ссылаться на функциюg
. Теперь, если вы всегда применяете входные данные к функцииg
(и используете ее несколько раз); что-то вроде этого:Вы должны ввести лямбду, потому что она экономит 1 байт для каждого дополнительного использования:
Обратное также может быть правдой
В случае самореферентной лямбды (
φχψ
) есть особый случай, когда вы применяете входные данные непосредственно к рекурсивной функции, в этих случаях вам лучше использовать индекс₀
вместо определения новой лямбды и использования⁰
.источник
Использование
Γ
Основное использование встроенной функции
Γ
, известной как сопоставление с образцом в списках или деконструкция списка , состоит в том, чтобы разбить список на голову и хвост и применить к ним двоичную функцию. Это соответствует идиоме паттерна Хаскеллагде
<something>
это выражение , содержащееx
,xs
и , возможноf
. Есть 4 перегрузкиΓ
, каждая из которых работает немного по-своему.list
Первая перегрузка,
list
принимает значениеa
и двоичную функциюf
. Он возвращает новую функцию, которая принимает список, возвращает,a
если он пуст, и вызываетf
голову и хвост , если он не пуст . Например,Γ_1€
принимает список, возвращает,-1
если он пуст, и индекс первого появления первого элемента в хвосте, если нет.listN
Вторая перегрузка,
listN
аналогичнаlist
, за исключением того, чтоa
она опущена, и вместо нее используется значение по умолчанию возвращаемого типа. Например,Γ€
эквивалентноΓ0€
, поскольку числовое значение по умолчанию -0
.На практике
listN
используется чаще, чемlist
, поскольку значение по умолчанию либо не имеет значения, либо именно то, что вам нужно. Распространенная картинаΓ~αβγ
, гдеαβγ
три функция; это относитсяβ
к первому элементу иγ
к хвосту и объединяет результаты сα
. Он был использован, например, в этом ответе . Другие шаблоны включают в себяΓo:α
применениеα
только к первому элементу иΓ·:mα
применениеα
ко всем элементам, кроме первого. Последний был использован в этом ответе .listF
Третья перегрузка немного сложнее. Мол
list
, он принимает значениеa
и функциюf
и возвращает новую функцию,g
которая принимает список. Однако на этот раз онf
получает дополнительный аргумент функции, которыйg
сам по себе, и может вызывать его для любого значения (включая, но не ограничиваясь этим, конец списка ввода). Это означает, чтоlistF
реализует общую схему рекурсии в списках.listF
используется не очень часто, поскольку явная рекурсия сlist
/listN
обычно такой же длины или короче, как в этом ответе .listNF
listNF
являетсяlistF
то , чтоlistN
этоlist
: входa
опущен, а значение по умолчанию типа возвращаемого используются вместо этого. В редких случаях он может быть короче правого сгиба, например, в этом ответе .В качестве примера рекурсивных версий
Γ
функцияΓλ·:o⁰↔
перетасовывает список в следующем порядке: первый, последний, второй, второй-последний, третий, третий-последний и так далее. Попробуйте онлайн! Функцияf
- это явная лямбдаλ·:o⁰↔
, аргументом которой⁰
является вся функция. Чтоf
делает, так это обратный хвост↔
, затем рекурсивный вызов главной функцииo⁰
и, наконец, возврат головы·:
. Конечно,Γ·:o₀↔
это на байт короче, но не работает, если строка содержит что-то еще, кроме этой функции.источник
Комбинаторы могут применяться к функциям высшего порядка
Предположим, у вас есть список целых чисел X , и вы хотите подсчитать общее количество элементов X , которые больше длины (X) . Counting элементы , которые удовлетворяют предикат делаются с функциями высшего порядка
#
, но здесь предикат (будучи больше длинами (X) ) зависит от X . Решение состоит в том, чтобы применить комбинаторṠ
к#
и функцию ,o>L
которая проверяет , является ли список короче , чем число. В функцииṠ#o>L
список X передаетсяo>L
, частично примененная функция передается#
, а X задается#
как второй аргумент.В общем случае, если
α
функция высшего порядка,β
бинарная функция иγ
унарная функцияṠαβ
эквивалентны псевдокоду Haskell§αβγ
эквивалентнои
~αβγ
эквивалентнодо тех пор, пока типы совпадают.
В качестве другого конкретного примера
§►δṁ≠P
находит перестановку списка X, которая максимизирует сумму абсолютных разностей с соответствующими значениями X (δṁ≠
объединяет два списка с использованием абсолютной разности и берет сумму).источник
Значения по умолчанию для шелухи
Husk не так строг, как Haskell, когда вы сталкиваетесь с проблемами, когда, например, вы пытаетесь получить
last
элемент пустого списка. Для достижения этого он использует предопределенные значения, вот список значений по умолчанию, максимумов и минимумов:* Здесь ∞ должен представлять бесконечный список соответствующего максимума (см. Пример ниже)
Примечание. Для кортежей (X, Y) будут использоваться значения для каждого компонента отдельно.
Когда они используются
В то время как максимумы и минимумы используются только для
▲▼
пустых списков (например,husk -u "▼" "[]:LLN"
будет возвращать бесконечный списокInf
), значения по умолчанию используются в нескольких местах:F
иḞ
)Θ
)r
) не удается←→
) или индексация в один (!
)Γ
) в пустых списках►
или◄
в пустых спискахисточник