LINUX.ORG.RU

Возврат значения из замыкания


0

4

Как вы считаете, если противопоставить, какое _и почему_ в абстрактном ЯП поведение оператора return внутри замыкания более правильное/оправданное: когда return только возвращает управление из замыкания или когда return вызванный внутри замыкания приводит ещё и к возврату из контекста, откуда было вызвано замыкание?

p.s. В качестве примера второго поведения - return из Proc в Ruby.

★★

Последнее исправление: maxcom (всего исправлений: 1)
Ответ на: комментарий от drBatty

нормально, что программа НЕ падает, когда у неё хватает памяти.

Ну так когда памяти хватает - никакие программы не падают. С чего бы им падать?

anonymous
()
Ответ на: комментарий от drBatty

ну открой глазки и посмотри на код.

Открыл, посмотрел. Не увидел там символа «=». Повторяю вопрос - что ты имел ввиду, когда говорил «равно»? Ты можешь на него отвтетиь? или ты не знаешь ответа?

anonymous
()
Ответ на: комментарий от psikh

В x86 нет никакого for. Ты идиот.

почему ты так уверен?

Потому, что его там нет, идиот. Потому, что там есть только условные и безусловные переходы, идиот.

что, правда? а как же

  400618:	c7 45 fc 01 00 00 00 	mov    DWORD PTR [rbp-0x4],0x1
  40061f:	eb 18                	jmp    400639 <main+0x29>
  400621:	8b 45 fc             	mov    eax,DWORD PTR [rbp-0x4]
  400624:	89 c6                	mov    esi,eax
  400626:	bf 3c 07 40 00       	mov    edi,0x40073c
  40062b:	b8 00 00 00 00       	mov    eax,0x0
  400630:	e8 5b fe ff ff       	call   400490 <printf@plt>
  400635:	83 45 fc 01          	add    DWORD PTR [rbp-0x4],0x1
  400639:	83 7d fc 0b          	cmp    DWORD PTR [rbp-0x4],0xb
  40063d:	7e e2                	jle    400621 <main+0x11>
?

drBatty ★★
()
Ответ на: комментарий от psikh

Ты настолько ничтожество, что даже сам не в состоянии осознать степень своей ничтожности.

слив засчитан.

drBatty ★★
()
Ответ на: комментарий от drBatty

ты заблуждаешься. В выражении a+b+c попросту нет никакого значения a+b.

Нету. Именно это я и сказал.

anonymous
()
Ответ на: комментарий от psikh

Иди, идиот, почитай, что такое выражение, и почему у выражения всегда есть значение.

где прочитать-то? ну расскажи мне, где написано, что есть значение у a+b в выражении a+b+c?

drBatty ★★
()
Ответ на: комментарий от drBatty

что, правда? а как же

И где в этом коде «for»? mov - вижу. jmp - вижу. call, add, cmp, jle - вижу. for - не вижу. Так на какой архитектуре мне исполнять for?

anonymous
()
Ответ на: комментарий от anonymous

Как обычно, в ответ на пруф «я в домике, кукареку». Ничего что codebase у racket как раз миллионы строк говнокода?

//fixed

drBatty ★★
()
Ответ на: комментарий от anonymous

И где в этом коде «for»? mov - вижу. jmp - вижу. call, add, cmp, jle - вижу. for - не вижу.

вот иди почитай свою библию SICP, там рассказано, что такое «синтаксический сахар». Вот for и есть - сахар.

drBatty ★★
()
Ответ на: комментарий от drBatty

Нет, ну это просто праздник какой-то. Ты настолько запредельно тупой и неграмотный, что даже не понимаешь, когда тебя смешивают с грязью. Прелестно! Побольше бы таких, как ты - на фоне подобных ничтожеств я себя Эйнштейном ощущаю!

psikh
()
Ответ на: комментарий от drBatty

вот иди почитай свою библию SICP, там рассказано, что такое «синтаксический сахар». Вот for и есть - сахар.

Вот хвостовая рекурсия в ФП - это и есть сахар.

anonymous
()
Ответ на: комментарий от anonymous

Открыл, посмотрел. Не увидел там символа «=». Повторяю вопрос - что ты имел ввиду, когда говорил «равно»? Ты можешь на него отвтетиь? или ты не знаешь ответа?

тупорылое созданьице:

для тебя специально код повторю:

(progn (setf (cdr x) x)
         (values))
drBatty ★★
()
Ответ на: комментарий от drBatty

Так что значит «равно» и какое отношение к значению этого термина имеет приведенный код?

anonymous
()
Ответ на: комментарий от psikh

Нет, ну это просто праздник какой-то. Ты настолько запредельно тупой и неграмотный, что даже не понимаешь, когда тебя смешивают с грязью. Прелестно! Побольше бы таких, как ты - на фоне подобных ничтожеств я себя Эйнштейном ощущаю!

проблема в том, что ты меня не понимаешь. Может потому, что я идиот, а ты дебил, и у тебя олегофрения не настолько запущена...

drBatty ★★
()
Ответ на: комментарий от psikh

Твоя мамка тебя слишком часто роняла башкой об пол, очевидно.

за то твоя тебя один раз уранила. Этого в принципе уже достаточно.

drBatty ★★
()
Ответ на: комментарий от anonymous

Я три раза перечитал, протер глаза и все же это вижу.

Сахар - это расширение синтаксиса. TCO не является таковым.

x4DA ★★★★★
()
Ответ на: комментарий от x4DA

for в сишке тоже не является, но у товарища свои собственные определения. работаем в их рамках.

anonymous
()
Ответ на: комментарий от anonymous

Обойдись без for

Так же, как обойдусь и без рекурсии - if и goto.

Что вовсе не значит, что аргумент этого идиота имеет хоть какой-то смысл. Что вызов функции, что goto - одинаково низкоуровневые понятия в железе. Часто (например в ARM) это вообще одно и то же.

psikh
()

При стандартизации CL этот вопрос очень долго обсуждался. Решение ИМХО идеально, но в других языках (вроде D) продолжают изобретать какие-то костыли.

А в CL просто return-from возвращает из именованного блока, например, функции. Лямбда - это неименованный блок и из неё можно вернуть просто return'ом. Заодно решили проблему вложенных функций. По имени можно вернуть из любой.

naryl ★★★★★
()
Ответ на: комментарий от psikh

Я описал тривиальный случай - первой строкой проекта на много миллионов строк идет (defmacro LOOP ...).

Пользователь внес в эту строку изменение.

Не знаю, сделай C-x C-e в Slime на любой форме - образ сразу инкрементально обновиться и во всех буферах будут уже новые подсказки и т.п.

В нем используются макросы, в определении которых использовались функции, которые использовали макрос LOOP.

А тут я уже не пойму предполагаемый use case. Я понимаю, если ты изменил _одну_ функцию или макрос в одном файле, закинул изменение в образ, пошёл в другой файл «за много миллионов строк» и всё у тебя работает с _именно этой_ функцией или макросом по части подсказок, документации, дополнений и подсветки (потому что образ). Но что именно ты хочешь от обновлённого LOOP который используется косвенно и явно в исходнике не фигурирует, то есть что вообще от IDE нужно?

quasimoto ★★★★
()
Ответ на: комментарий от psikh

Для говнолиспа принципиально неотслеживаемы, и потому надо перекомпилировать ВЕСЬ код.

(pxref:list-callers 'loop) как-то находит ровно тот код который завязан на изменяемый макрос. Правда я не вижу в Slime возможности скомандовать обновить весь зависимый от макроса код, так что нужно либо обходить вручную, либо грузить asdf снова.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

невиснушего кода, который выводит циклический список на сишке

#include <stdio.h>

struct list { int x; struct list *xs; };

void print(struct list *z)
{
    if (z) {
        printf("%d", z->x);
        for (struct list *p = z->xs; p; p = p->xs) {
            if (p == z) {
                printf(", ...");
                break;
            }
            printf(", %d", p->x);
        }
        puts("");
    }
}

int main()
{
    struct list z1 = { 3, NULL }, z2 = { 2, &z1 }, z3 = { 1 , &z2 };
    print(&z3);
    z1.xs = &z3;
    print(&z3);
}
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Правда я не вижу в Slime возможности скомандовать обновить весь зависимый от макроса код, так что нужно либо обходить вручную, либо грузить asdf снова.

C-M-x (slime-eval-defun) - оно? http://restas.lisper.ru/ru/manual/slime.html

anonymous
()
Ответ на: комментарий от quasimoto

Осталось исправить, чтоб z1.xs = &z2 работал, и будет хорошо.

staseg ★★★★★
()
Ответ на: комментарий от anonymous

(slime-eval-defun) - оно?

Не оно. Evaluate the current toplevel form. Я однажды так и не нашел решения и перезагружаю .asd. //По ссылке речь вообще не о том.

staseg ★★★★★
()
Ответ на: комментарий от anonymous

for в сишке тоже не является

for идеально вписывается в определение синтаксического сахара.

staseg ★★★★★
()
Ответ на: комментарий от anonymous

А если теперь список зациклен на второй элемент а не на первый?

Я только для линейных и полностью цикличных списков делал. Для циклов в середину можно так сделать:

struct list *find_cycle_node(struct list *z)
{
    if (z) {
        int i = 0;
        for (struct list *p = z->xs; p; p = p->xs, ++i) {
            int j = 0;
            for (struct list *q = z; j < i && q; q = q->xs, ++j)
                if (p == q) return p;
        }
    }

    return NULL;
}

void print(struct list *z)
{
    int n = -1;
    bool before_cycle_node = true;
    struct list *cycle_node = find_cycle_node(z);

    for (struct list *p = z; p; p = p->xs) {
        if (before_cycle_node) ++n;
        if (p == cycle_node) {
            if (before_cycle_node) {
                before_cycle_node = false;
            } else {
                printf("-> %d(%d)[%p]", n, p->x, p);
                break;
            }
        }
        printf("%d ", p->x);
    }

    puts("");
}

Тут поиск узла - O(n^2), но лучше я не придумал.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Я чего-то не понимаю или от тебя не ожидал... Простой список же. Поиск цикла, петли и ручки - тривиальная задача...

anonymous
()
Ответ на: комментарий от anonymous

Поиск цикла, петли и ручки - тривиальная задача...

Тогда расскажи как нужно. Floyd's cycle-finding algorithm, например, не находит точного местоположения узла, только детектирует сам цикл.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

А если циклов много?

А как создать связный список в котором много циклов?

Кстати, *print-circle* работать не только с cons-ами но и с произвольными циклическими структурами. Правда наличие *circularity-hash-table* в sbcl/src/code/print.lisp подсказывает, что SBCL делает это тупо заводя таблицу посещённых объектов (так что будет O(n) ещё и по памяти). Но для общего случая и для печати (не очень приоритетная задача) это, в принципе, самое то.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Почему не подходит? Может я чего и не понял, но

struct list *
find_collision_node(struct list *z)
{
    if (!z)
        return z;

    struct list *slw = z;
    struct list *fst = z->xs;

    while (fst != slw) {
        slw = slw->xs;
        if (!fst)
            return fst;
        fst = fst->xs;
        if (!fst)
            return fst;
        fst = fst->xs;
    }

    return fst;
}
Ну а то, что ты у себя назвал cycle_node - это просто xs от точки стокновения. Ня? Или я туплю?

anonymous
()
Ответ на: комментарий от anonymous

Почему не подходит?

Потому что заяц будет догонять черепаху в совершенно произвольном месте?

С твоей find_collision_node такой код:

int main()
{
    {
        struct list z1 = {1, NULL};
        printf("1, *%p\n", find_collision_node(&z1));
        z1.xs = &z1;
        printf("1 -> 1, 1[%p] == *[%p]\n", &z1, find_collision_node(&z1));
    }

    {
        struct list z1 = {1, NULL}, z2 = {2, &z1};
        printf("2 1, *%p\n", find_collision_node(&z2));
        z1.xs = &z1;
        printf("2 1 -> 1, 1[%p] == *[%p]\n", &z1, find_collision_node(&z2));
        z1.xs = &z2;
        printf("2 1 -> 2, 2[%p] == *[%p]\n", &z2, find_collision_node(&z2));
    }

    {
        struct list z1 = {1, NULL}, z2 = {2, &z1}, z3 = {3, &z2};
        printf("3 2 1, *%p\n", find_collision_node(&z3));
        z1.xs = &z1;
        printf("3 2 1 -> 1, 1[%p] == *[%p]\n", &z1, find_collision_node(&z3));
        z1.xs = &z2;
        printf("3 2 1 -> 2, 2[%p] == *[%p]\n", &z2, find_collision_node(&z3));
        z1.xs = &z3;
        printf("3 2 1 -> 3, 3[%p] == *[%p]\n", &z3, find_collision_node(&z3));
    }

    {
        struct list z1 = {1, NULL}, z2 = {2, &z1}, z3 = {3, &z2}, z4 = {4, &z3};
        printf("4 3 2 1, *%p\n", find_collision_node(&z4));
        z1.xs = &z1;
        printf("4 3 2 1 -> 1, 1[%p] == *[%p]\n", &z1, find_collision_node(&z4));
        z1.xs = &z2;
        printf("4 3 2 1 -> 2, 2[%p] == *[%p]\n", &z2, find_collision_node(&z4));
        z1.xs = &z3;
        printf("4 3 2 1 -> 3, 3[%p] == *[%p]\n", &z3, find_collision_node(&z4));
        z1.xs = &z4;
        printf("4 3 2 1 -> 4, 4[%p] == *[%p]\n", &z4, find_collision_node(&z4));
    }
}

печатает

1, *(nil)
1 -> 1, 1[0x7fff00fa9bc0] == *[0x7fff00fa9bc0]
2 1, *(nil)
2 1 -> 1, 1[0x7fff00fa9bb0] == *[0x7fff00fa9bb0]
2 1 -> 2, 2[0x7fff00fa9ba0] == *[0x7fff00fa9bb0]
3 2 1, *(nil)
3 2 1 -> 1, 1[0x7fff00fa9b90] == *[0x7fff00fa9b90]
3 2 1 -> 2, 2[0x7fff00fa9b80] == *[0x7fff00fa9b80]
3 2 1 -> 3, 3[0x7fff00fa9b70] == *[0x7fff00fa9b90]
4 3 2 1, *(nil)
4 3 2 1 -> 1, 1[0x7fff00fa9b60] == *[0x7fff00fa9b60]
4 3 2 1 -> 2, 2[0x7fff00fa9b50] == *[0x7fff00fa9b60]
4 3 2 1 -> 3, 3[0x7fff00fa9b40] == *[0x7fff00fa9b50]
4 3 2 1 -> 4, 4[0x7fff00fa9b30] == *[0x7fff00fa9b60]

то есть находит узел только в случае списка из одного элемента, а в других случаях это будет произвольный (но детерминированный, конечно) элемент списка, вовсе не узел - просто место где fst догнал slw.

С моей find_cycle_node в качестве find_collision_node получается правильно:

1, *(nil)
1 -> 1, 1[0x7fff52ae6e40] == *[0x7fff52ae6e40]
2 1, *(nil)
2 1 -> 1, 1[0x7fff52ae6e30] == *[0x7fff52ae6e30]
2 1 -> 2, 2[0x7fff52ae6e20] == *[0x7fff52ae6e20]
3 2 1, *(nil)
3 2 1 -> 1, 1[0x7fff52ae6e10] == *[0x7fff52ae6e10]
3 2 1 -> 2, 2[0x7fff52ae6e00] == *[0x7fff52ae6e00]
3 2 1 -> 3, 3[0x7fff52ae6df0] == *[0x7fff52ae6df0]
4 3 2 1, *(nil)
4 3 2 1 -> 1, 1[0x7fff52ae6de0] == *[0x7fff52ae6de0]
4 3 2 1 -> 2, 2[0x7fff52ae6dd0] == *[0x7fff52ae6dd0]
4 3 2 1 -> 3, 3[0x7fff52ae6dc0] == *[0x7fff52ae6dc0]
4 3 2 1 -> 4, 4[0x7fff52ae6db0] == *[0x7fff52ae6db0]

так что

то, что ты у себя назвал cycle_node - это просто xs от точки стокновения

Нет, это точка столкновения, например для

3 -> 2 -> 1
     ^    |
     `----,

find_cycle_node найдёт 2, так что адрес 2 будет в cycle_node, print пройдёт до него, то есть до начала цикла, переключит before_cycle_node, пройдёт цикл один раз опять до cycle_node, напишет что 2 это узел и сделает break.

Можно захардкодить find_cycle_node и print в одну print с двумя for, либо не париться, завести хеш и делать один for, либо кто-то должен рассказать как сделать с одним for за O(n) по времени и O(1) по памяти.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Хм. Я пьян, но я попробую понять и ответить=) Но может быть лучше в другой раз. Спс за разъяснения.

anonymous
()
Ответ на: комментарий от quasimoto

Я правда настолько пьян, что не вижу разницы в том, что ты привел, между результатом твоей функции и моей?

anonymous
()
Ответ на: комментарий от quasimoto

Какова изначальная задача?

anonymous
()
Ответ на: комментарий от quasimoto

А, так надо добавить:

struct list *
find_cycle_node(struct list *z)
{
    struct list *y = find_collision_node(z);
    if (!y)
        return y;
    y = y->xs;
    while (z != y) {
        z = z->xs;
        y = y->xs;
    }
    return z;
}
Это я и имел в виду под тем, что «то, что ты называешь find_cycle_node будет просто xs от find_collision_node». Просто не совсем так выразился=) Теперь ня?

anonymous
()
Ответ на: комментарий от anonymous

Ну и функцию печати тоды тоже переделаем(а то что-то путанная):

void
print_list(struct list *z)
{
    struct list *cycle_node = find_cycle_node(z);
    int n = 0;
    for(; z != cycle_node || cycle_node && n++ == 0; z = z->xs)
        printf(" --> {%p : %d}", z, z->x);
    printf(" --> [%p]\n", z);
}

anonymous
()
Ответ на: комментарий от quasimoto

Итого:

struct list {
    int x;
    struct list *xs;
};

struct list *
find_collision_node(struct list *z)
{
    if (!z)
        return z;

    struct list *slw = z;
    struct list *fst = z->xs;

    while (fst != slw) {
        slw = slw->xs;
        if (!fst)
            return fst;
        fst = fst->xs;
        if (!fst)
            return fst;
        fst = fst->xs;
    }

    return fst;
}

struct list *
find_cycle_node(struct list *z)
{
    struct list *y = find_collision_node(z);
    if (!y)
        return y;
    y = y->xs;
    while (z != y) {
        z = z->xs;
        y = y->xs;
    }
    return z;
}

void
print_list(struct list *z)
{
    struct list *cycle_node = find_cycle_node(z);
    int n = 0;
    for(; z != cycle_node || cycle_node && n++ == 0; z = z->xs)
        printf(" --> {%p : %d}", z, z->x);
    printf(" --> [%p]\n", z);
}

int
main()
{
    /*
      [1] -> [2] -> [3] -> [4] -> (nil)
    */
    struct list z1 = { 1, NULL }, z2 = { 2, NULL }, z3 = { 3, NULL }, z4 = { 4, NULL };
    z1.xs = &z2;
    z2.xs = &z3;
    z3.xs = &z4;

    print_list(&z1);

    /*
      [1] -> [2] -> [3] -> [4] ---+
       ^                          |
       |                          |
       +--------------------------+
    */
    z4.xs = &z1;
    print_list(&z1);

    /*
      [1] -> [2] -> [3] -> [4] ---+
              ^                   |
              |                   |
              +-------------------+
    */
    z4.xs = &z2;
    print_list(&z1);

    /*
      [1] -> [2] -> [3] -> [4] ---+
                     ^            |
                     |            |
                     +------------+
    */
    z4.xs = &z3;
    print_list(&z1);

    /*
      [1] -> [2] -> [3] -> [4] ---+
                            ^     |
                            |     |
                            +-----+
    */
    z4.xs = &z4;
    print_list(&z1);
}

Выводит:

 --> {0xbf9a7390 : 1} --> {0xbf9a7398 : 2} --> {0xbf9a73a0 : 3} --> {0xbf9a73a8 : 4} --> [(nil)]

 --> {0xbf9a7390 : 1} --> {0xbf9a7398 : 2} --> {0xbf9a73a0 : 3} --> {0xbf9a73a8 : 4} --> [0xbf9a7390]

 --> {0xbf9a7390 : 1} --> {0xbf9a7398 : 2} --> {0xbf9a73a0 : 3} --> {0xbf9a73a8 : 4} --> [0xbf9a7398]

 --> {0xbf9a7390 : 1} --> {0xbf9a7398 : 2} --> {0xbf9a73a0 : 3} --> {0xbf9a73a8 : 4} --> [0xbf9a73a0]

 --> {0xbf9a7390 : 1} --> {0xbf9a7398 : 2} --> {0xbf9a73a0 : 3} --> {0xbf9a73a8 : 4} --> [0xbf9a73a8]

Вроде пашет. Но ты пиши, если я накосячил чего=)

anonymous
()
Ответ на: комментарий от quasimoto

А как создать связный список в котором много циклов?

Добро пожаловать в DrRacket, версия 5.2.1 [3m].
Язык: racket [выбранный].
> (define yoba (mcons 10 20))
> (set-mcar! yoba yoba)
> (set-mcdr! yoba yoba)
> yoba
#0=(mcons #0# #0#)
> 
anonymous
()
Ответ на: комментарий от anonymous

Обойдись без for.

в сишечке? да без проблем! можно даже и без do/while, просто функциями.

drBatty ★★
()
Ответ на: комментарий от anonymous

for в сишке тоже не является

в каком месте сишечке тебе так уж необходим for? Это типичный сахар, и с лёгкостью меняется на другие конструкции (if/goto, do/while, ФП). В принципе, ничего не мешает использовать только if/goto (кроме неиллюзорных пиз*й от того, кто этот код будет поддерживать)

drBatty ★★
()
Ответ на: комментарий от psikh

Что вовсе не значит, что аргумент этого идиота имеет хоть какой-то смысл. Что вызов функции, что goto - одинаково низкоуровневые понятия в железе.

не совсем так. call из x86 это такой «железный сахар» над операциями со стеком и с jmp.

drBatty ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.