p
\Ai
\&
>(&]&|0
<*&d
&~bN
10
( )/+
/*
Спробуйте в Інтернеті!
Пояснення
Це, на сьогоднішній день, найдосконаліша (а також найдовша) програма, яку я написав у «Медузи» поки що. Я не маю ідеї, чи зможу це зрушити в зрозумілій формі, але, мабуть, мені доведеться спробувати.
Медузи забезпечують досить загальний оператор ітерації \
, який дуже допомагає "знайти Nth щось ". Однією з його семантики є "ітерація функції по значенню, поки окрема тестова функція не дає чогось правдоподібного" (насправді тестова функція отримує і поточний, і останній елемент, але ми лише змусимо її подивитися на поточний елемент) . Ми можемо використовувати це для реалізації функції "Наступне дійсне число". Ще одне перевантаження " \
це повторити функцію на вихідне значення N разів". Ми можемо скористатися нашою попередньою функцією та повторити її в 0
N разів, де N - вхід. Все це налаштовано досить стисло з цією частиною коду:
p
\Ai
\&
> 0
(Причини того 0
, що фактичний вхід до отриманої функції закінчується, є дещо складними, і я тут не вдаваюся в них.)
Проблема у всьому цьому полягає в тому, що ми не передамо поточне значення тестовій функції вручну. \
Оператор зробить це за нас. Отже, тепер ми побудуємо єдину функцію одинарної функції (за допомогою композицій, гачків, вилок і каррі), яка приймає число і повідомляє нам, чи дійсне це число (тобто таке, яке ділиться на його цифру на суму і цифру продукту). Це досить нетривіально, коли ви не можете посилатися на аргумент. Колись. Це ця краса:
(&]&|
<*&d
&~bN
10
( )/+
/*
Це (
унарний гак , що означає, що він викликає функцію нижче ( f
) на своєму вході (поточне значення x
), а потім передає їх обоє тестовій функції праворуч ( g
), тобто це обчислює g(f(x), x)
.
У нашому випадку - f(x)
це ще одна складова функція, яка отримує пару з цифровим твором і сумою цифр x
. Це означає g
, що функція, яка має всі три значення, перевіряє, чи справді x
вона.
Почнемо з розгляду того, як f
обчислюється цифра суми та цифрного добутку. Це f
:
&~b
10
( )/*
/+
&
також є композиція (але навпаки). ~
currying, тому 10~b
дає функцію, яка обчислює десяткові цифри числа, і оскільки ми передаємо &
це праворуч, це перше, що станеться з введенням x
. Решта використовує цей список цифр для обчислення їх суми та добутку.
Щоб обчислити суму, ми можемо скласти над нею додавання, що є /+
. Аналогічно, для обчислення продукту ми складаємо множення на нього /*
. Для об'єднання обох цих результатів у пару ми використовуємо пару гачків (
та )
. Структура цього:
()g
f
(Де f
і g
є добуток і сума відповідно.) Спробуємо розібратися, чому це дає нам пару f(x)
і g(x)
. Зауважте, що правий гак )
має лише один аргумент. У цьому випадку мається на увазі інший аргумент, ;
який обертає свої аргументи в парі. Крім того, гачки також можуть бути використані як бінарні функції (що буде тут), і в цьому випадку вони просто застосовують внутрішню функцію лише до одного аргументу. Тож дійсно )
по одній функції g
дає функція, яка обчислює [x, g(y)]
. Використовуючи це в лівому гачку, ми разом f
отримуємо [f(x), g(y)]
. Це, в свою чергу, використовується в одинарному контексті, а це означає, що він насправді викликається x == y
і тому ми закінчуємо [f(x), g(x)]
необхідне. Phew.
Це залишає лише одне, що було нашою попередньою функцією тестування g
. Нагадаємо, що він буде називатися так, g([p, s], x)
де x
все ще знаходиться поточне вхідне значення, p
є його цифровим добутком і s
є його цифрова сума. Це g
:
&]&|
<*&d
N
Щоб перевірити подільність, ми, очевидно, будемо використовувати модуль, який є |
у медуз. Дещо незвично він бере правого операнда по модулю його лівий операнд, а це означає, що аргументи g
вже в правильному порядку (арифметичні функції, подібні до цього, автоматично передаються по списках, тому це обчислить дві окремі модулі безкоштовно) . Наше число ділиться як на добуток, так і на суму, якщо результат - пара нулів. Щоб перевірити, чи це так, ми розглядаємо пару як список базових 2 цифр ( d
). Результат цього дорівнює нулю, лише тоді, коли обидва елементи пари дорівнюють нулю, тому ми можемо заперечити результат цього ( N
), щоб отримати триєдне значення за тим, чи розділяють вхідні обидва значення. Слід зазначити , що |
, d
іN
просто всі складені разом з парою &
s.
На жаль, це ще не повна історія. Що робити, якщо розрядний добуток дорівнює нулю? Ділення і модуль на нуль обидва повертають нуль у медуз. Хоча це може здатися дещо дивним умовою, воно насправді виявляється дещо корисним (адже нам не потрібно перевіряти нуль, перш ніж робити модуль). Однак це також означає, що ми можемо отримати помилковий позитивний результат, якщо цифра суми розділяє вхід, але цифровий добуток дорівнює нулю (наприклад, введення 10
).
Ми можемо це виправити, помноживши результат ділення на цифровий добуток (так що, якщо цифровий добуток дорівнює нулю, він перетворить і наше нульове значення на нуль). Виявляється, простіше помножити результат поділу на пару продукту і суму, а потім отримати результат з продукту.
Щоб помножити результат на пару, нам якось потрібно повернутися на більш раннє значення (пара). Це робиться виделкою ( ]
). Вилки як би гачки на стероїдах. Якщо ви дасте їм дві функції f
і g
вони являють собою бінарну функцію , яка обчислює f(a, g(a, b))
. У нашому випадку a
- це продукт / сума пари, b
є поточним вхідним значенням, g
є нашим тестом на роздільність і f
є множенням. Отже, все це обчислюється [p, s] * ([p, s] % x == [0, 0])
.
Все, що залишилося зараз, - це отримати перше значення цього, яке є кінцевим значенням тестової функції, що використовується в ітераторі. Це так само просто, як складати ( &
) виделку з головною функцією <
, яка повертає перше значення списку.