(~!)(!)((~)~*):((!)~^)*(:^)(~(!)~^(~)~*)(()~(~)~^~*)
Спробуйте в Інтернеті! (включає тестовий набір та текст, що ідентифікує частини програми)
Це дивно добре для дуже низького рівня езолангу. (Церковні цифри, церковні булеви тощо) дуже часто використовуються в програмі Underload з цієї причини; в мові немає вбудованих чисел і булів, і це один із найпростіших способів їх моделювання. Однак, це також є загальним для кодувати булеви як церковні цифри 0 і 1.)
Для тих, хто плутається: Underload дозволяє визначати функції багаторазового використання, але не дозволяє вам називати їх звичайним чином, вони просто сортуються навколо стеку аргументів (тому, якщо ви визначите п'ять функцій, а потім хочете викликати першу Ви визначили, вам потрібно написати нову функцію, яка бере п'ять аргументів і викликає п'ятий з них, а потім називати її недостатньо багатьма аргументами, щоб вона шукала запасні аргументи для використання). Виклик їх знищує їх за замовчуванням, але ви можете змінити виклик, щоб зробити його неруйнівним (у простих випадках потрібно просто додати двокрапку до виклику, хоча складні випадки є більш поширеними, оскільки вам потрібно переконатися, що копії на стеку не заважає), тому підтримка функції Underload має всі вимоги, які нам знадобляться з питання.
Пояснення
правда
(~!)
( ) Define function:
~ Swap arguments
! Delete new first argument (original second argument)
Цей досить простий; ми позбавляємось аргументу, який ми не хочемо, і аргумент, який ми хочемо, просто залишається там, слугуючи як повернене значення.
помилковий
(!)
( ) Define function:
! Delete first argument
Цей ще простіший.
ні
((~)~*)
( ) Define function:
~* Modify first argument by pre-composing it with:
(~) Swap arguments
Це одне задоволення: not
взагалі не називає свого аргументу, він просто використовує функціональну композицію. Це звичайний трюк в "Underload", в якому ви взагалі не перевіряєте свої дані, ви просто змінюєте їх функціонування, попередньо і після складання речей з ним. У цьому випадку ми змінюємо функцію, щоб заміняти її аргументами перед запуском, що явно заперечує число Церкви.
і
:((!)~^)*
( ) Define function:
~^ Execute its first argument with:
(!) false
{and implicitly, our second argument}
* Edit the newly defined function by pre-composing it with:
: {the most recently defined function}, without destroying it
Питання дозволяє визначити функції з точки зору інших функцій. Ми визначаємо "і" далі, оскільки чим нещодавно було визначено "не", тим простіше його використовувати. (Це не віднімається від нашої оцінки, тому що ми взагалі не називаємо "не", але це економить байти при написанні визначення знову. Це єдиний раз, коли одна функція посилається на іншу, оскільки посилається на будь-яку функцію але останнє визначене коштуватиме занадто багато байтів.)
Визначення тут таке and x y = (not x) false y
. Іншими словами, якщо not x
, тоді ми повертаємось false
; інакше ми повертаємось y
.
або
(:^)
( ) Define function:
: Copy the first argument
^ Execute the copy, with arguments
{implicitly, the original first argument}
{and implicitly, our second argument}
@Nitrodon зазначив у коментарях, що or x y = x x y
зазвичай коротше or x y = x true y
, і це виявляється правильним і в Underload. Наївна реалізація цього була б (:~^)
, але ми можемо відібрати додатковий байт, зазначивши, що не має значення, чи будемо ми запускати оригінальний перший аргумент чи його копію, і результат є тим самим.
Навантаження насправді не підтримує currying у звичному розумінні, але такі визначення, як це, виглядають так, як це є! (Хитрість полягає в тому, що невикористані аргументи просто затримуються, тому функція, яку ви викликаєте, буде інтерпретувати їх як власні аргументи.)
мається на увазі
(~(!)~^(~)~*)
( ) Define function:
~ Swap arguments
~^ Execute the new first (original second) argument, with argument:
(!) false
{and implicitly, our second argument}
(~)~* Run "not" on the result
Тут використовується визначення implies x y = not (y false x)
. Якщо у істинно, це спрощується not false
, тобто true
. Якщо y помилково, це спрощується not x
, тим самим даючи нам таблицю правди, яку ми хочемо.
У цьому випадку ми not
знову використовуємо , цього разу переписуючи його код, а не посилаючись на нього. Він просто написаний безпосередньо як (~)~*
без дужок навколо нього, тому його називають, а не визначають.
xor
(()~(~)~^~*)
( ) Define function:
~ ~^ Execute the first argument, with arguments:
(~) "swap arguments"
() identity function
~* Precompose the second argument with {the result}
Цього разу ми оцінюємо лише один із наших двох аргументів і використовуємо його для визначення того, що слід скласти на другому аргументі. Underload дозволяє вам грати швидко і вільно з суворістю, тому ми використовуємо перший аргумент для вибору між двома аргументаційними двома аргументаційними функціями; аргумент своп, який повертає їх як у протилежному порядку, так і функція ідентичності, яка повертає їх обох у тому ж порядку.
Коли перший аргумент є істинним, тому ми виробляємо відредаговану версію другого аргументу, яка міняє своїми аргументами перед запуском, тобто попередньо створює "аргументи swap", тобто not
. Отже, справжній перший аргумент означає, що ми повертаємо not
другий аргумент. З іншого боку, помилковий перший аргумент означає, що ми складаємось із функцією тотожності, тобто нічого не робимо. Результатом є реалізація xor
.