Underload - это полуфункциональный брезент на основе стека, созданный ais523 . Я недавно пытался играть в гольф, потому что это удивительно элегантный язык.
Какие у вас есть советы по игре в гольф в Underload? (Один совет за ответ)
Underload - это полуфункциональный брезент на основе стека, созданный ais523 . Я недавно пытался играть в гольф, потому что это удивительно элегантный язык.
Какие у вас есть советы по игре в гольф в Underload? (Один совет за ответ)
Ответы:
*
для выводаПоскольку вы можете выводить, оставляя строку в стеке , может быть полезно накопить строку, используя *
вместо вывода с помощью S
. Скажем, ваша задача заключалась в том, чтобы «взять строку и добавить пробел», способ сделать это с помощью вывода:
S( )S
С *
другой стороны, способ сделать это на один байт короче:
( )*
Проблема в том, что если ваш вывод имеет много накоплений, он может стоить байтов для обработки выходного элемента в стеке.
Если вам нужно много использовать фрагмент кода, имеет смысл сохранить этот код в стеке и время от времени дублировать и оценивать его. Пока что это просто нормальное программирование под нагрузкой. К сожалению, долгое время хранить значение в стеке сложно, и это приводит к тому, что ваш код становится многословным, и это верно, даже если значение является функцией, а не данными. Это становится намного хуже, если у вас есть несколько функций, которые необходимо использовать повторно.
В более крупной программе, которая может извлечь выгоду из нескольких повторно используемых функций, решение, которое вы можете использовать, состоит в том, чтобы вместо этого создать одну большую функцию, которая может выполнять любые свои задачи в зависимости от того, как она вызывается (либо на основе того, что находится под ней в стеке, или через использование более длинных последовательностей вызова , чем просто ^
, тщательно написанная функция может отличить ^^
от ^:^
от ^*^
от ^~^
, давая вам четыре различных, довольно короткие последовательности). Вы также можете хранить другие полезные вещи, такие как строки, которые вы используете несколько раз, в этом «словаре». Обратите внимание, что если вы интенсивно используете словарь, возможно, имеет смысл сделать его своего рода квинэном, перенеся его копию обратно в стек, чтобы вам не приходилось копировать его вручную с помощью:
быть в состоянии использовать это, не теряя способность использовать это в будущем.
^!!!!^
стилем поиска (который я также использовал в нескольких других примерах на странице, особенно в разделе минимизации.) Хотя это может не дать кратчайшего поиска.
В качестве простого примера, наиболее часто встречающаяся реализация логических значений относится !()
к ложному (т. Е. Целому 0) и к нулевой строке для истинного (т. Е. Целому 1), но если у вас есть проблема, которая в значительной степени основана на логическом XOR, она может сделать больше смысл использовать пустую строку для false и ~
для true (этот формат данных может быть преобразован в любой другой логический формат с использованием (false)~(true)~^!
и позволяет очень краткую реализацию *
для XOR.
Можно пойти дальше этого общего принципа и использовать функции, которые понадобятся вашей программе позже, как часть ваших значений данных; это избавляет от необходимости хранить функции и данные отдельно в стеке. Это может сделать процесс управления более запутанным, но при игре в гольф ремонтопригодность часто приходится занимать заднее сиденье, и в любом случае недогрузка не так уж и полезна.
(!)
и (~!)
для логических, но ваш путь кажется лучше.
Функционально-чистый способ уменьшить церковную цифру - использовать функцию-предшественник лямбда-исчисления:
\n.n(\p.\z.z($(pT))(pT))(\z.z0[whatever you define the predecessor of 0 to be])
Где 0 = \ x. \ Yy, T = \ x. \ Yx и $ - преемник.
Переписано в Underload, это 28 байтов:
(!())~(!())~(!:(:)~*(*)*~)~^!
Это нормально, но мы можем использовать некоторые из полезных свойств Underload, а именно, что они :!
и ()*
являются no-ops. Это означает , что, для ряда n
, :ⁿ!!()()*ⁿ
(где cⁿ
в c
повторном n
раз) дает N-1. Например, делая это для церковной цифры 3, получим следующее:
:::!!()()***
Сняв безоперационные пары, мы получим:
:*
Который 2.
Итак, это новая и более короткая предшествующая операция:
:(:)~^(!!()())*~(*)~^*
Это на 7 байт короче.
(()~(:))~:(^!!())*~(*)~^**
все равно на 3 байта короче.
Недостаточная нагрузка на самом деле имеет два стека - стек строк и стек команд, составляющих исходный код. Инструкция Underload ^
позволяет нам перемещать строки из первого стека во второй. Делая это, мы можем сохранить много ненужных манипуляций со стеком.
Например, скажем, у нас есть (a)(b)(c)
основной стек, и мы хотим объединить два нижних элемента, игнорируя (c)
, чтобы получить (ab)(c)
. Наивный способ сделать это состоит в том, чтобы повернуть стек, чтобы получить, (c)(a)(b)
а затем собрать и вернуть обратно:
a~a~*~a*^*~
Это плохо. Использование a~a~*~a*^
для вращения стека таким образом чрезвычайно дорого, и по возможности его следует избегать. (c)
Вместо этого, поместив в пространство программы, это можно сделать на четыре байта короче:
a(*)~*^
Идея состоит в том, чтобы взять инструкции, которые вы хотели бы выполнить, а затем добавить инструкцию, чтобы отодвинуть ее (c)
в конце, и затем оценить результат. Это означает, что нам не нужно беспокоиться, (c)
пока он не отодвинется после того, как мы закончим.
(*)~a*^
, что я думаю, что это немного более сложным. По сути ~a*^
это dip
команда от Радости.
eval
команда, я никогда раньше не видел такого языка.