Open Rorifer opened 8 years ago
Формально это называется косвенная хвостовая рекурсия. Более простой (не косвенный) вариант той же ситуации:
#ali {тест} {#out $tick;#math tick {$tick+1};тест}
тест
В случае жабы это транслируется в чистом виде в рекурсивные вызовы parse_input(...)
в ядре TinTin.
Проблема рекурсии в том, что она жрёт стек, а это не совсем обычный "буффер". Его можно увеличить, но необходимость этого, как правило, свидетельствует о неправильно выбранных алгоритмах в принципе, и в данном случае приведет к увеличению возможной глубины вызовов максимум на порядок, что как-то грустно всё равно. Ведь, например, хвостовая рекурсия однозначно сворачивается в цикл и, соответственно, жрать стек перестаёт вовсе. Также целесообразней TinTin'у самому управлять отдельным стеком под выполнение команд, выделять его динамически и не зависеть от "собственного" стека в этом плане.
Я набросал предварительный фикс, выполняющий в случае хвостовой и некоторых других видах рекурсии произвольное количество вызовов, а в остальных -- ограниченное выделяемой ОС памятью. Но это серьёзное изменение модели вычислений TinTin'а вообще, так что весьма вероятно, что что-то сломалось, хотя на моих конфигах всё ок. После выполнения некоторой оптимизации и всестороннего тестирования, если всё будет хорошо, я сделаю соответствующий пулл-реквест. Тут будет очень полезна реализация идеи Романа: нужен какой-то скрипт-файл (типа *.set-файлов), например selftest.set, такой, чтобы запустив из жабы #read selftest.set
можно было относительно легко понять, нормально всё работает, или что-то сломалось. Мои собственные конфиги весьма скудны в плане set-файлов, так что не уверен, что смогу сделать достаточно всеобъемлющие тесты. Простое всякое -- легко, но извращения типа
#var x #a;#var y {lias fo};#var z {o bar}
$x$y$z
вряд ли переберу, особенно со всякими вложенными if-ами с одноимёнными переменными.
Тут очень хочется напомнить Правило Гринспуна. Моё сугубо личное, но очень глубокое убеждение: не следует воспринимать TinTin как среду для сколь-нибудь серьезных вычислений; это должен быть простой как топор и надёжный доступ к примитивным и базовым вещам: подключение, горячие клавиши, логирование, прокси, сжатие, промпт... Смотрите сами: #if
ущербен, #math
убог, #action
ограничен, притом всё это довольно сложные для понимания, плохо документированные и зачастую контринтуитивные конструкты (с этими их %%1, "}" и т.п.). Есть поддержка ActiveScript: это и javascript, и python, и lua, и кому что нравится вообще. Всё это отработанные во множестве областей десятками тысяч программистов и сотнями миллионов юзеров инструменты, многие идеально подходят для любых MUD-задач. Очень простые для изучения, со множеством примеров, широким комьюнити, понятными книгами для начинающих. И тут совершенно легко и естественно пишутся хоть БД предметов/мобов, хоть боты, хоть мапперы: для TinTin'а задачи совершенно неподъёмные.
Спасибо за столь развернутый ответ. Полностью согласен со всем сказанным. Тогда может как-то можно ограничить рекрсивную функцию, чтоб она хоть жабу не крешила... Что то типа при заполнении стека в 20 команд не ждать до 30 с последующим вылетом, а к примеру стопнуть все циклы, обнулить стек и вывести сообщение в мейн об ошибке? 16 марта 2016 г. 20:24 пользователь "konelav" notifications@github.com написал:
Формально это называется косвенная хвостовая рекурсия https://en.wikipedia.org/wiki/Tail_call. Более простой (не косвенный) вариант той же ситуации:
ali {тест} {#out $tick;#math tick ($tick+1};тест}
В случае жабы это транслируется в чистом виде в рекурсивные вызовы parse_input(...) в ядре TinTin.
Проблема рекурсии в том, что она жрёт стек, а это не совсем обычный "буффер". Его можно увеличить, но необходимость этого, как правило, свидетельствует о неправильно выбранных алгоритмах в принципе, и в данном случае приведет к увеличению возможной глубины вызовов максимум на порядок, что как-то грустно всё равно. Ведь, например, хвостовая рекурсия однозначно сворачивается в цикл и, соответственно, жрать стек перестаёт вовсе. Также целесообразней TinTin'у самому управлять отдельным стеком под выполнение команд, выделять его динамически и не зависеть от "собственного" стека в этом плане.
Я набросал предварительный фикс, выполняющий в случае хвостовой и некоторых других видах рекурсии произвольное количество вызовов, а в остальных -- ограниченное выделяемой ОС памятью. Но это серьёзное изменение модели вычислений TinTin'а вообще, так что весьма вероятно, что что-то сломалось, хотя на моих конфигах всё ок. После выполнения некоторой оптимизации и всестороннего тестирования, если всё будет хорошо, я сделаю соответствующий пулл-реквест. Тут будет очень полезна реализация идеи Романа https://github.com/nerevar/jmc/pull/46#issuecomment-182070905: нужен какой-то скрипт-файл (типа *.set-файлов), например selftest.set, такой, чтобы запустив из жабы #read selftest.set можно было относительно легко понять, нормально всё работает, или что-то сломалось. Мои собственные конфиги весьма скудны в плане set-файлов, так что не уверен, что смогу сделать достаточно всеобъемлющие тесты. Простое всякое -- легко, но извращения типа
var x #a;#var y {lias fo};#var z {o bar}
$x$y$z вряд ли переберу, особенно со всякими вложенными if-ами с одноимёнными переменными.
Тут очень хочется напомнить Правило Гринспуна https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule. Моё сугубо личное, но очень глубокое убеждение: не следует воспринимать TinTin как среду для сколь-нибудь серьезных вычислений; это должен быть простой как топор и надёжный доступ к примитивным и базовым вещам: подключение, горячие клавиши, логирование, прокси, сжатие, промпт... Смотрите сами: #if ущербен, #math убог, #action ограничен, притом всё это довольно сложные для понимания, плохо документированные и зачастую контринтуитивные конструкты (с этими их %%1, "}" и т.п.). Есть поддержка ActiveScript: это и javascript, и python, и lua, и кому что нравится вообще. Всё это отработанные во множестве областей десятками тысяч программистов и сотнями миллионов юзеров инструменты, многие идеально подходят для любых MUD-задач. Очень простые для изучения, со множеством примеров, широким комьюнити, понятными книгами для начинающих. И тут совершенно легко и естественно пишутся хоть БД предметов/мобов, хоть боты, хоть мапперы: для TinTin'а задачи совершенно неподъёмные.
— You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub https://github.com/nerevar/jmc/issues/51#issuecomment-197442171
Да, конечно, это же рекурсия и её нужно ограничивать.
Например, выполнять следующий шаг итерации, только, если $tick
будет меньше какого-то значения, 30 например:
#ali {тест1}{#out $tick1;#math {tick1}{$tick1+1};#if {$tick < 30} {тест2}}
#ali {тест2}{#out $tick1;#math {tick1}{$tick1+1};#if {$tick < 30} {тест1}}
Роман, ограничение этого действия руками пользователя понятно. я говорю о защите от.. невнимательности в случае косвенной рекурсии 20 марта 2016 г. 23:31 пользователь "Roman Rybalchenko" < notifications@github.com> написал:
Да, конечно, это же рекурсия и её нужно ограничивать. Например, выполнять следующий шаг итерации, только, если $tick будет меньше какого-то значения, 30 например.
— You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub
При формировании бесконечного цикла команд - жабу крешит при накоплении како-то буфера.. т.е. набор тригеров:
var tick1 0
ali {тест1}{#out $tick1;#math {tick1}{$tick1+1};тест2}
ali {тест2}{#out $tick1;#math {tick1}{$tick1+1};тест1}
крешит 3.6.1.1 при 53 операциях. 3.0.5 при 32 операции. 3.26 при 80 операциях А теперь вопрос =) можно как то увеличить буфер? Креш я так понимаю из за переполнения очереди команд происходит ведь?