Дальше, как уже всегда, начинаем писать факториал на языке. Вслед за автором замечу что для определения факториала не были использованы ни циклы, ни рекурсия.
Как и в случае с
K или с
бэкФортом нам понадобится операция генерирующая ряд натуральных чисел от 1 до n, где n -- аргумент.
В определении этой функции используется то что числа в Enchilada также являются списками, пусть их элементы и пусты. Помним?
Код:
> 3 [1] *|
[1;1;1]
Или, если посмотреть с другой стороны:
Код:
> [1] 3 *`
[1;1;1]
Аналогично:
Код:
> [1] [1] + [1] +
[1;1;1]
А теперь что называется, "следи за рукой" (с):
Код:
> 4 ["1+] *:`
[" 1 +;" 1 +;" 1 +;" 1 +]
Здесь у нас в скобках по сути тело цикла, которое мы "умножаем", чтобы получить его нужное количество раз.
Но циклу нужно начальное значение (чтобы самому первому " -- DUP'у было чего дублировать), поэтому добавляем единичку:
Код:
> 4 1:["1+] *:`
1 [" 1 +;" 1 +;" 1 +;" 1 +]
Потом просто выводим "раскрученный" цикл за скобки операцией ! . Этот пример я покажу в режиме отладки:
Код:
> \ost 4 1:["1+] *:`!
0: 4 1 : [" 1 +] * : ` !
1: 1 4 [" 1 +] * : ` !
2: 1 4 [" 1 +;" 1 +;" 1 +;" 1 +] : ` !
3: 1 [" 1 +;" 1 +;" 1 +;" 1 +] 4 ` !
4: 1 [" 1 +;" 1 +;" 1 +;" 1 +] !
5: 1 " 1 + " 1 + " 1 + " 1 +
6: 1 1 1 + " 1 + " 1 + " 1 +
7: 1 2 " 1 + " 1 + " 1 +
8: 1 2 2 1 + " 1 + " 1 +
9: 1 2 3 " 1 + " 1 +
10: 1 2 3 3 1 + " 1 +
11: 1 2 3 4 " 1 +
12: 1 2 3 4 4 1 +
13: 1 2 3 4 5
Последнее число нам не нужно, поэтому его надо убирать, добавляем ещё один ` -- DROP. То есть функция готова:
Код:
iotaN == 1:["1+] *:`!`
(вот только определение функций у меня не получаются, ошибки какие-то)
Заметьте, что результат функции -- ряд чисел мы получаем на стеке, а не в списке-элемента стека.
Теперь нужно перемножить полученный натуральный ряд, чтобы получить факториал. Принцип такой же:
Код:
mulN == 1:[*`] :* ! !
Обратите внимание, mulN берёт со стека одно значение -- нужное кол-во умножений.
А полностью факториал из учебника выглядит так:
Код:
facN == ^ [iotN; mulN] * | !
Сходу что делает facN не особо понять... Первая операция берёт значение с вершины стека и заключает его в скобки, превращая в список. Уже знакомая нам комбинация *|! делает map, но как бы наоборот... Так как у "данных" один элемент, а "функций" две, то Декартово произведение их даст последовательное выполнение обеих функций с одним и тем же аргументом:
Код:
12 ^ [iotN; mulN] * |
[12] [iotN; mulN] * |
[12 iotN;12 mulN]
Затем ! выполняет всё остальное, сначала выполняет 12 iotN , он оставляет на стеке ряд чисел, потом выполняется 12 mulN , который делает 12 нужных нам умножений на стеке, сводя всё к одному значению -- факториалу.
Вот так он считается в режиме трассировки:
Код:
0: 3 ^ [1 : [" 1 +] * : ` ! `;1 : [* `] : * ! !] * | !
1: [3] [1 : [" 1 +] * : ` ! `;1 : [* `] : * ! !] * | !
2: [3;3] [1 : [" 1 +] * : ` ! `;1 : [* `] : * ! !] | !
3: [3 1 : [" 1 +] * : ` ! `;3 1 : [* `] : * ! !] !
4: 3 1 : [" 1 +] * : ` ! ` 3 1 : [* `] : * ! !
5: 1 3 [" 1 +] * : ` ! ` 3 1 : [* `] : * ! !
6: 1 3 [" 1 +] * : ` ! ` 1 3 [* `] : * ! !
7: 1 3 [" 1 +] * : ` ! ` 1 [* `] 3 * ! !
8: 1 3 [" 1 +] * : ` ! ` 1 [* `;* `;* `] 3 ! !
9: 1 3 [" 1 +;" 1 +;" 1 +] : ` ! ` 1 [* `;* `;* `] 3 ! !
10: 1 [" 1 +;" 1 +;" 1 +] 3 ` ! ` 1 [* `;* `;* `] 3 ! !
11: 1 [" 1 +;" 1 +;" 1 +] ! ` 1 [* `;* `;* `] 3 ! !
12: 1 " 1 + " 1 + " 1 + ` 1 [* `;* `;* `] 3 ! !
13: 1 1 1 + " 1 + " 1 + ` 1 [* `;* `;* `] 3 ! !
14: 1 2 " 1 + " 1 + ` 1 [* `;* `;* `] 3 ! !
15: 1 2 2 1 + " 1 + ` 1 [* `;* `;* `] 3 ! !
16: 1 2 3 " 1 + ` 1 [* `;* `;* `] 3 ! !
17: 1 2 3 3 1 + ` 1 [* `;* `;* `] 3 ! !
18: 1 2 3 4 ` 1 [* `;* `;* `] 3 ! !
19: 1 2 3 1 [* `;* `;* `] 3 ! !
20: 1 2 3 1 [* `;* `;* `] !
21: 1 2 3 1 * ` * ` * `
22: 1 2 3 3 ` * ` * `
23: 1 2 3 * ` * `
24: 1 6 6 ` * `
25: 1 6 * `
26: 6 6 `
27: 6
Хм.. Я бы сделал как-нибудь иначе, но хояин -- барин...