Способ фон Неймана может быть неудобен в этом случае, а может быть проще представлять числа как
[],
[[]],
[[[]]],
[[[[]]]], …
Из-за того, что я предложил довольно либеральный язык — функции любого числа аргументов, рекурсия… — то если реализовать ноль, прибавление единицы и возможность проверять, ноль перед нами или не ноль, и вычитать из последнего единицу, мы сможем реализовать произвольную машину Минского, с помощью которых можно довольно удобно выразить вычисления над натуральными числами для такого круга вопросов (вычислимые функции, эквивалентность вычислительных моделей и пр.).
Код получится как у вас, но брать предыдущее число от чисел, закодированных как у меня, проще (единственный элемент оно и есть). Ещё мне жаль, что я не ввёл конструкцию, похожую на матчинг, например с такой записью:
Код:
switch (s)
case 0 {
// выполняется, если s == 0
}
case [x, *xs] {
// выполняется, если s != 0, притом
// x = select(s) и xs = s - x
}
а отдельный
select удалить как нежелательный. Теперь язык не нуждается в вываливании с ошибкой посреди кода. И тогда эта конструкция очень хорошо ляжет на кодирование машин Минского этим языком, потому что она в точности реализует, если
s код числа, команду JZDEC, или как я её там звал.
И ещё будем считать, что язык игнорирует переменные с именем
_, это в матчинге полезно.
Вот код, аналогичный вашему, но с вычитанием и делением, и я не стану заводить отдельную функцию для последователя числа, раз это просто
[n]:
Код:
prev(x) { // ниже prev не используется
switch (x)
case 0 { return 0; } // лучше уж так, когда нам вообще пригодится prev в виде функции
case [prev_x, *_] { return prev_x; }
}
add(x, y) {
switch (x)
case 0 { return y; }
case [prev_x, *_] { return add(prev_x, [y]); }
}
// Два варианта вычитания, достаточно полезных для натуральных чисел
sub(x, y) { // truncated subtraction
switch (x)
case 0 { return 0; }
case [prev_x, *_] {
switch (y)
case 0 { return x; }
case [prev_y, *_] {
return sub(prev_x, prev_y);
}
}
}
sub2(x, y) { // symmetric subtraction
return add(sub(x, y), sub(y, x)) // если лень определять его с нуля
}
not(x) { // непусто тогда, когда x == 0, и наоборот
switch (x)
case 0 { return [0]; }
case [_, *_] { return 0; }
}
eq(x, y) { // непусто ровно когда x == y
return not(sub2(x, y)) // можно и минимальнее, конечно, опять же
}
mult(x, y) {
switch (x)
case 0 { return 0; }
case [prev_x, *_] { return add(y, mult(prev_x, y)); }
}
div(x, y) {
// ife (y) { return 0; } // раскомментировать, если не хотим зацикливания при делении на ноль
ifne (sub(x, y) + eq(x, y)) { // если x > y или x == y
return [div(sub(x, y), y)];
}
else {
return 0;
}
}
и так даже дойдём до вычисления пар Кантора и сможем реализовать целые числа как пары натуральных, рациональные как тройки и так далее…
-- Пт мар 20, 2020 05:00:22 --Ой, я всю эту страницу пропустил как-то, извините.
-- Пт мар 20, 2020 05:05:11 --Да и отрицательные числа сделать хочется (вопрос: как их реализовать и не поломают ли они функцию сложения?)...
Парой натурального со знаком может быть не очень удобно, а может и быть, ну и пара из двух, вида
или
(хотя можно брать вообще все, а к такому каноническому виду приводить через раз).
Любую пару множеств можно, конечно, сделать множеством ([a, [a, b]]), но как же операции реализовывать тогда?
-- 20 мар 2020, 02:44 --
Удобнее даже [[a], [[a], [b]]], кажись.
А вот про возможность выражать пары средствами самого языка, не уходя в числа, я забыл! Надо подумать, это могло бы быть в каком-то смысле быстрее, если мы вдруг начнём оптимизировать количество операций.
-- Пт мар 20, 2020 05:17:19 --Тут так и быть попользуюсь ещё
selectом. Пара Куратовского
нормально отыгрывает, можно не добавлять вложенности (а вот снять скобки с одинокого икса будет уже чревато обработкой кучи лишнего):
Код:
cons(x, y) { // для нелисперов, это собрание в пару
return [[x], [x, y]]
}
car(p) { // для нелисперов, это извлечение первого элемента пары
a = select(p);
b = select(p);
c = select(a);
ife (a) { return c; }
d = select(b);
ife (b) { return d; }
}
cdr(p) { // для нелисперов, это извлечение второго элемента пары
a = select(p);
b = select(p);
c = select(a);
d = select(b);
ife (a) {
ife (c ~ d) {
e = select(b);
return e;
}
else { return d; }
}
ife (b) {
ife (c ~ d) {
e = select(a);
return e;
}
else { return c; }
}
}
-- Пт мар 20, 2020 05:28:41 --А, ну в кодах выше надо читать
[] вместо
0, вроде такого раньше не было.