spamsink: (lenin)
[personal profile] spamsink


Внезапно захотелось странного: возможности рекурсивно вызвать вызвавшую функцию с заменой некоторых ее аргументов согласно определенному правилу. Например, у меня есть
void foo(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
    ...
    if (сложное условие) {
        T3 newArg3 = сложное вычисление;
        return foo(arg1, arg2, newArg3, arg4);
    }
    ...
}
и
T5 bar(T1A arg1, T2A arg2, T3 arg3) {
    ...
    if (то же самое сложное условие) {
        T3 newArg3 = то же самое сложное вычисление;
        return bar(arg1, arg2, newArg3);
    }
    ...
}

Как прикажете выфакторизовывать сложное условие и сложное вычисление? В идеале (псевдокод) было бы что-то вроде
Maybe T baz(данные для вычисления условия и newArg3) {
// "Maybe void" must be == bool.
    if (сложное условие) {
        return Just recurseParent(map (3 => сложное вычисление));
    }
    return None;
}

void foo(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
    ...
    if (baz(...)) {
        return;
    ...
}

T5 bar(T1A arg1, T2A arg2, T3 arg3) {
    ...
    Maybe T5 val = baz(...);
    if (val != None)
        return val;
    ...
}


Какой-нибудь язык сейчас так может?

Date: 2016-07-21 12:27 am (UTC)
From: [identity profile] archaicos.livejournal.com
longjmp/throw?

Date: 2016-07-21 01:45 am (UTC)
From: [identity profile] archaicos.livejournal.com
Тогда я запутался. В первых примерах у тебя вроде и так всё хорошо (кроме расхода стека). То, что я предложил, даёт возможность оборвать исполнение вызванной ф-ции с возвратом, откуда можно сделать повторный вызов с другим аргументом (лишнего расхода стека нет). А чего ещё нужно?

Date: 2016-07-21 02:43 am (UTC)
From: [identity profile] yatur.livejournal.com
Сдается мне, что ничего проще выделения этих сложных условий с свои собственные функции не получится.

bool complexCondition(...);
T3 complexCalculation(...);

void foo(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
   ...
    if (complexCondition(params)) {
        foo(arg1, arg2, complexCalculation(...), arg4);
        return;
    }
    ...
}


Возможно, тут можно замутить какую-нибудь супер-пупер сверхмонаду на тригенных куаторах, но простой код будет потом проще отлаживать и проще поддерживать.

Date: 2016-07-21 03:51 am (UTC)
From: [identity profile] ticklish-frog.livejournal.com
std::optional baz(T1 arg1, T2 arg2) {
return (сложное условие) ? сложное вычисление : std::optional();
}

и потом

void foo(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
// ...
const auto& maybe = baz(arg1, arg2);
if (maybe) {
return foo(arg1, arg2, maybe.value(), arg4);
}
// ...
}

мне было бы так проще тестировать и поддерживать baz, чем если бы baz кого-то вызывал.

Можно еще поиграть с __func__ / __FUNCTION__.

#define MAYBE_RETURN_MAPPED_SELF(arg, ...) \
do { \
if (condition(arg, ##__VA_ARGS__)) \
return __func__ (mapping(arg), ##__VA_ARGS__) \
} while(false)

Я не знаю, правда, сработает ли это, может, надо обернуть в ##, всегра использовал __func__ в строчном контексте.

Date: 2016-07-21 04:35 am (UTC)
From: [identity profile] juan-gandhi.livejournal.com
Во-первых, надо каррировать.
Во-вторых, если проблема с рекурсией, то поможет trampolining.
Скала, грубо говоря, все это предоставляет (в реале есть определенные сложности, но не сильно).

Date: 2016-07-21 11:51 am (UTC)
From: [identity profile] http://users.livejournal.com/_guard_/
Ну, в JS есть динамический объект arguments, а также Function.caller

http://jsbin.com/yimizuf/1/edit?js,console,output

Date: 2016-07-21 02:19 pm (UTC)
From: [identity profile] http://users.livejournal.com/_guard_/
Я слаб в высоких материях, пришлось почитать в википедии. Насколько я понимаю, речь идет о замыкании выражения с текущим контекстом и получении функции, которая, будучи вызванной, вернет результат вычисления выражения.

Так как в JS нет поддержки абстрактных выражений как структур первого класса, в чистом виде этого, кажется, добиться нельзя (свободные переменные замыкаются в функцию при её объявлении). Я попробовал с такими мерзопакостными вещами, как with и new Function, но не вышло.

Однако нашлись какие-то papers от умных людей, сейчас почитаем.

Date: 2016-07-21 02:29 pm (UTC)
From: [identity profile] http://users.livejournal.com/_guard_/
В общем, то, что я нашел, полагается на некую фичу, реализованную только в Rhino, древней (по нынешним меркам) имплементации JS на Java.

Так что кажется, что всё-таки нельзя.
Page generated Mar. 7th, 2026 11:03 am
Powered by Dreamwidth Studios