LINUX.ORG.RU
ФорумTalks

Добавил поддержку корутин в свою реализацию Кумира

 ,


0

2

Предыдущая серия про Кумир тут: Компилятор русского языка программирования Кумир

Если кратко то я добавил поддержку корутин. На синтаксисе это никак не отразилось, а вот во внутреннем языке оно есть. Это позволило в частности сделать нормальную анимацию в браузере.

Например, есть код анимации задачи n-тел:

использовать Рисователь

  алг
  нач
      вещ таб x[0:N-1], y[0:N-1], vx[0:N-1], vy[0:N-1]
      вещ таб tx[0:N-1, 0:TAIL-1], ty[0:N-1, 0:TAIL-1]
      цел frame

      инициализировать(x, y, vx, vy, tx, ty)
      новый лист(W, H, чёрный)

      frame := 0
      нц пока да
          шаг_физики(x, y, vx, vy, tx, ty)
          нарисовать(frame, x, y, tx, ty)
          frame := frame + 1
      кц
  кон

  алг шаг_физики(...)
  нач
      | обычный CPU-код, без команд Рисователя
  кон

  алг нарисовать(...)
  нач
      | рисуем кадр
      окружность(int(CX), int(CY), 12)
      ...
      окружность(int(x[i]), int(y[i]), 2)

      | граница кадра / suspend point
      новый лист(W, H, чёрный)
  кон

Трансляция во внутренний язык (ast, core-lang):

(fun <main> void () ()
    (block
      ...
      (call инициализировать x y vx vy tx ty)
      (call |новый лист| W H чёрный)
      (= frame 0)
      (while
        #t
        (block
          (call шаг_физики x y vx vy tx ty)
          (call нарисовать frame x y tx ty)
          (= frame (+ frame 1))))))

  (fun шаг_физики void (...) ()
    (block
      ...))

  (fun нарисовать void (...) ()
    (block
      ...
      (call окружность (call int CX) (call int CY) 12)
      ...
      (call окружность (call int (index i x)) (call int (index i y)) 2)
      (call |новый лист| W H чёрный)))

Тут «новый лист» это на самом деле переход к новому фрейму. Это корутина. Данный ast трансформируется в

(fun <main> <future void> () ()
    (block
      ...
      (call инициализировать x y vx vy tx ty)

      ;; прямой suspend point: painter_new_sheet / "новый лист"
      (await (call |новый лист| W H (: 4278190080 <named цвет i64>)))

      (= frame 0)
      (while
        (cast 1 bool)
        (block
          ;; обычная функция: не стала корутиной
          (call шаг_физики x y vx vy tx ty)

          ;; транзитивный await:
          ;; main ждёт нарисовать, потому что нарисовать внутри вызывает новый лист
          (await (call нарисовать frame x y tx ty))

          (= frame (+ frame 1))))))

  (fun шаг_физики void (...) ()
    (block
      ...))

  (fun нарисовать <future void> (...) ()
    (block
      ...
      (call окружность (call int CX) (call int CY) 12)
      ...
      (call окружность (call int (index i x)) (call int (index i y)) 2)

      ;; локальный suspend point, из-за него вся функция стала Future<void>
      (await (call |новый лист| W H (: 4278190080 <named цвет i64>)))))

То есть автоматом ставится await и все вызывающие функции транзитивно становятся корутинами. Это позволяет прыгнуть в js, сделать отрисовку, а потом прыгнуть назад в кумир.

Демка: http://qumir.dev/s/ZTZjYjM2NzRk

Звезды ставить сюда: https://github.com/resetius/qumir

★★★★★

Последнее исправление: Reset (всего исправлений: 1)

Например, есть код анимации задачи n-тел:

Я вставил верхнюю часть твоей писанины к тебе на страницу в окно редактора. Перенажимал все кнопки. Ничего не произошло. Как запустить твоё поделие?

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

Я снипет в пост вставил, а не полную программу, для запуска специально сделал быструю ссылку :) Вот еще раз ссылка: http://qumir.dev/s/ZTZjYjM2NzRk

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

Надо было так: координата_по_оси_X, координата_по_оси_Y, скорость_по_оси_X, скорость_по_оси_Y

хѣръ, ижица, ижица-хѣръ, ижица-ѹкъ

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

икс, игрэк, скорость_икс, скорость_игрек или х, у, вх, ву? Ну чтобы набирать, не переключаясь. Кстати в официальной IDE есть временное переключение раскладки по AltGr, только у меня не работало. Нужно чтобы набирать []{} в основном.

Xenius ★★★★★
()

В полноценном императивном языке программирования должны быть как минимум структуры (связанные в одну переменную разнородные данные) и указатели, у тебя их похоже нет.

Что-то роскомопозор не даёт грузить CSS с сайта, поэтому загружаются какие-то разнородные иконки и не работает.

Кстати можно их gzip сжать как workaround. Он даёт по 15 килобайт грузить, а у тебя где-то вдвое больше.

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

В полноценном языке прогроммирования должны быть как минимум алгебраические типы, а императивность с указателями загнаны в подвал и не отсвечивать, и await лучше всё таки явный.

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

У меня на капсе стоит - не особо напрягает

У меня тоже. Но такое частое переключение напрягло бы.

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

В core-lang в который делается трансляция есть все. А в кумире их изначально не было, я придерживаюсь оригинального синтаксиса. Можно конечно прагмы добавить со своими расширениями.

Через структуры сделаны комплексные числа. Через указатели передача значений по ссылке (арг рез в сигнатурах), а также массивы

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

Что-то роскомопозор не даёт грузить CSS с сайта, поэтому загружаются какие-то разнородные иконки и не работает.

Печаль. Попробую посмотреть под русским vpn вечером

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

А нужны ли прагмы? Просто сделать расширение не противоречащее оригиналу?

Зато имея структуры и указатели можно делать деревья, списки и прочие штуки и написать компилятор языка на нём самом.

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

Интерпретатор кумира на кумире кстати есть и написан на массивах, на Хабре статья есть :)

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

В этой реализации ключевые слова регистрозависимые?

// Ещё мне кажется, что в русском ЯП слово «инициализировать» выглядит крайне всрато, и можно было бы подобрать аналог покороче и понативнее.

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

юс малый, юс большой и два йотированных же.

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

А смысл в интерпретаторе? Он ничего не даёт, только замедляет. Хотя конечно интересно сколько так можно сделать уровней вложенности. Надо компилятор.

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

Я далек пока от компилятора кумира на кумире. У меня кодогенерация зависит от llvm. Ну можно конечно сказать что генерируем не as, а llvm-as и звать потом llvm тулзу вместо as, но я не уверен что это хороший путь

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

Генерить любой asm тяжелее чем llvm ir так как надо делать аллокатор регистров и выбор инструкций

Reset ★★★★★
() автор топика

использовать Рисователь

алг

нач

  вещ

Кажется, хватит на сегодня интернета. Пойду спать.

Zhbert ★★★★★
()
Ответ на: комментарий от ya-betmen

какая-то не смишная шутка, что нормального в динамически типизированной эзотерической нечитаемой скриптухе и давно заслуженно мёртвой

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

Так ты сам написал критерии. Я просто подумал, что под них может подойти.

ya-betmen ★★★★★
()
Ответ на: комментарий от zurg

Обыватель не понял мощь перла, ему подавай что попроще

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

Само получилось. Я считаю что это эпохальное изменение. Тем более я этим проектом с декабря не занимался :)

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

А есть синоним всё / все и поддержка «если справа не стена» — втыкание не в середину многословных логических функций?

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

А есть синоним всё / все

Есть

втыкание не в середину многословных логических функций?

Нет такого. Я не осилил. Там и так из-за пробелов в идентификаторах лексер получился нетривиальным :)

Reset ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Верное замечаение. Вот так должно быть

использовать Рисователь

цел W = 900
цел H = 700
цел N = 64
цел TAIL = 20

вещ CX = 450.0
вещ CY = 350.0
вещ G = 1.0
вещ CENTRAL_MASS = 2400.0
вещ DT = 0.18
вещ SOFTENING2 = 36.0
вещ PI = 3.141592653589793

алг
нач
    вещ таб mass[0:N-1]
    вещ таб x[0:N-1], y[0:N-1], vx[0:N-1], vy[0:N-1]
    вещ таб ax[0:N-1], ay[0:N-1], nextAx[0:N-1], nextAy[0:N-1]
    вещ таб tx[0:N-1, 0:TAIL-1], ty[0:N-1, 0:TAIL-1]

    цел frame
    вещ t

    инициализировать(mass, x, y, vx, vy, tx, ty)
    вычислить_ускорения(mass, x, y, ax, ay)
    новый лист(W, H, чёрный)
    frame := 0
    t := 0.0

    нц пока да
        шаг_физики(mass, x, y, vx, vy, ax, ay, nextAx, nextAy, tx, ty)
        нарисовать(frame, t, x, y, tx, ty)
        frame := frame + 1
        t := t + DT
    кц
кон

алг инициализировать(арг рез вещ таб mass[0:N-1], арг рез вещ таб x[0:N-1], арг рез вещ таб y[0:N-1], арг рез вещ таб vx[0:N-1], арг рез вещ таб vy[0:N-1], арг рез вещ таб tx[0:N-1, 0:TAIL-1], арг рез вещ таб ty[0:N-1, 0:TAIL-1])
нач
    цел i, k
    вещ radius, angle, speed, speedScale
    вещ totalPx, totalPy

    mass[0] := CENTRAL_MASS
    x[0] := CX
    y[0] := CY
    vx[0] := 0.0
    vy[0] := 0.0
    totalPx := 0.0
    totalPy := 0.0

    нц для i от 1 до N - 1
        mass[i] := 0.7 + 1.8 * rnd(1.0)
        radius := 65.0 + 215.0 * rnd(1.0)
        angle := 2.0 * PI * rnd(1.0)
        speedScale := 0.96 + 0.08 * rnd(1.0)
        speed := sqrt(G * CENTRAL_MASS / radius) * speedScale

        x[i] := CX + radius * cos(angle)
        y[i] := CY + radius * sin(angle)
        vx[i] := -speed * sin(angle)
        vy[i] := speed * cos(angle)
        totalPx := totalPx + mass[i] * vx[i]
        totalPy := totalPy + mass[i] * vy[i]
    кц

    vx[0] := -totalPx / mass[0]
    vy[0] := -totalPy / mass[0]

    нц для i от 0 до N - 1
        нц для k от 0 до TAIL - 1
            tx[i, k] := x[i]
            ty[i, k] := y[i]
        кц
    кц
кон

алг вычислить_ускорения(вещ таб mass[0:N-1], вещ таб x[0:N-1], вещ таб y[0:N-1], арг рез вещ таб ax[0:N-1], арг рез вещ таб ay[0:N-1])
нач
    цел i, j
    вещ dx, dy, r2, invR, invR3, factor

    нц для i от 0 до N - 1
        ax[i] := 0.0
        ay[i] := 0.0
    кц

    нц для i от 0 до N - 2
        нц для j от i + 1 до N - 1
            dx := x[j] - x[i]
            dy := y[j] - y[i]
            r2 := dx * dx + dy * dy + SOFTENING2
            invR := 1.0 / sqrt(r2)
            invR3 := invR * invR * invR
            factor := G * invR3

            ax[i] := ax[i] + factor * mass[j] * dx
            ay[i] := ay[i] + factor * mass[j] * dy
            ax[j] := ax[j] - factor * mass[i] * dx
            ay[j] := ay[j] - factor * mass[i] * dy
        кц
    кц
кон

алг шаг_физики(вещ таб mass[0:N-1], арг рез вещ таб x[0:N-1], арг рез вещ таб y[0:N-1], арг рез вещ таб vx[0:N-1], арг рез вещ таб vy[0:N-1], арг рез вещ таб ax[0:N-1], арг рез вещ таб ay[0:N-1], арг рез вещ таб nextAx[0:N-1], арг рез вещ таб nextAy[0:N-1], арг рез вещ таб tx[0:N-1, 0:TAIL-1], арг рез вещ таб ty[0:N-1, 0:TAIL-1])
нач
    цел i, k

    | Velocity Verlet
    нц для i от 0 до N - 1
        x[i] := x[i] + vx[i] * DT + 0.5 * ax[i] * DT * DT
        y[i] := y[i] + vy[i] * DT + 0.5 * ay[i] * DT * DT
    кц

    вычислить_ускорения(mass, x, y, nextAx, nextAy)

    нц для i от 0 до N - 1
        vx[i] := vx[i] + 0.5 * (ax[i] + nextAx[i]) * DT
        vy[i] := vy[i] + 0.5 * (ay[i] + nextAy[i]) * DT
        ax[i] := nextAx[i]
        ay[i] := nextAy[i]

        нц для k от TAIL - 1 до 1 шаг -1
            tx[i, k] := tx[i, k - 1]
            ty[i, k] := ty[i, k - 1]
        кц
        tx[i, 0] := x[i]
        ty[i, 0] := y[i]
    кц
кон

алг нарисовать(цел frame, вещ t, вещ таб x[0:N-1], вещ таб y[0:N-1], вещ таб tx[0:N-1, 0:TAIL-1], вещ таб ty[0:N-1, 0:TAIL-1])
нач
    цел i, k
    цел hue, alpha, radius

    нц для i от 0 до N - 1
        если i = 0 то
            hue := 45
            radius := 8
        иначе
            hue := mod(div(i * 360, N) + div(frame, 4), 360)
            radius := 2
        все

        нц для k от TAIL - 1 до 1 шаг -1
            alpha := 16 + (TAIL - k) * 8
            перо(1, HSLA(hue, 85, 60, alpha))
            кисть(HSLA(hue, 85, 60, alpha))
            окружность(int(tx[i, k]), int(ty[i, k]), 1)
        кц

        перо(1, HSL(hue, 90, 65))
        кисть(HSL(hue, 90, 65))
        окружность(int(x[i]), int(y[i]), radius)
    кц

    шрифт("Arial", 13, нет, нет)
    перо(1, RGB(160, 160, 160))
    надпись(8, 18, "N-body, t = " + вещ_в_лит(t))

    новый лист(W, H, чёрный)
кон

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

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

(block
  (pragma language overloads)

  (fun rh_lookup_slot ((var keys <ptr <named Key (template readable mutable)>>)
                       (var dist <ptr i64>)
                       (var slot_ids <ptr i64>)
                       (var capacity i64)
                       (var key <named Key (template readable mutable)>)) -> i64
    (block
      (var slot = (& (call rh_hash key) (- capacity (: 1 i64))))
      (var probe_dist i64)
      (= probe_dist (: 0 i64))
      (while (< probe_dist capacity)
        (block
          (var resident_dist = (index dist slot))
          (if (|| (== resident_dist (: -1 i64)) (< resident_dist probe_dist))
            (block (return (: -1 i64))))
          (if (call rh_key_equal (index keys slot) key)
            (block (return (index slot_ids slot))))
          (= slot (& (+ slot (: 1 i64)) (- capacity (: 1 i64))))
          (= probe_dist (+ probe_dist (: 1 i64)))))
      (return (: -1 i64))))

  ;; Inserts a key known to be absent, assigning it dense_slot, with Robin
  ;; Hood displacement. Returns #f only when the table is unexpectedly full.
  (fun rh_insert_displace ((var keys <ptr <named Key (template readable mutable)>>)
                           (var dist <ptr i64>)
                           (var slot_ids <ptr i64>)
                           (var capacity i64)
                           (var key <named Key (template readable mutable)>)
                           (var dense_slot i64)) -> bool
    (block
      (var carried_key = key)
      (var carried_dist i64)
      (= carried_dist (: 0 i64))
      (var carried_slot = dense_slot)
      (var slot = (& (call rh_hash key) (- capacity (: 1 i64))))
      (var probes i64)
      (= probes (: 0 i64))
      (while (< probes capacity)
        (block
          (var resident_dist = (index dist slot))
          (if (== resident_dist (: -1 i64))
            (block
              (= keys [slot] carried_key)
              (= dist [slot] carried_dist)
              (= slot_ids [slot] carried_slot)
              (return #t)))
          (if (< resident_dist carried_dist)
            (block
              (var resident_key = (index keys slot))
              (var resident_slot = (index slot_ids slot))
              (= keys [slot] carried_key)
              (= dist [slot] carried_dist)
              (= slot_ids [slot] carried_slot)
              (= carried_key resident_key)
              (= carried_dist resident_dist)
              (= carried_slot resident_slot)))
          (= slot (& (+ slot (: 1 i64)) (- capacity (: 1 i64))))
          (= carried_dist (+ carried_dist (: 1 i64)))
          (= probes (+ probes (: 1 i64)))))
      (return #f)))

  (fun aht_update ((var ht <ref HashTable>)
                   (var key <named Key (template readable mutable)>)
                   (var value i64)) -> i64
    (block
      (var keys_typed =
        (cast (field ht Keys) <ptr <named Key (template readable mutable)>>))
      (var dense_slot = (call rh_lookup_slot keys_typed (field ht Dist)
                          (field ht SlotId) (field ht Capacity) key))
      (if (!= dense_slot (: -1 i64))
        (block
          (call agg_apply_reducers (field ht AggBuffers) dense_slot value #f)
          (return dense_slot)))
      (var capacity = (field ht Capacity))
      (var size = (field ht Size))
      (if (> (+ size (: 1 i64)) (- capacity (/ capacity (: 4 i64))))
        (block
          (if (> capacity (: 576460752303423487 i64)) (block (return (: -1 i64))))
          (if (! (call aht_rehash ht (* capacity (: 2 i64)) key))
            (block (return (: -1 i64))))
          (= capacity (field ht Capacity))))
      (= keys_typed
        (cast (field ht Keys) <ptr <named Key (template readable mutable)>>))
      (if (! (call rh_insert_displace keys_typed (field ht Dist) (field ht SlotId)
                    capacity key size))
        (block (return (: -1 i64))))
      (var group_typed =
        (cast (field ht GroupKeys) <ptr <named Key (template readable mutable)>>))
      (= group_typed [size] key)
      (var agg_buffers = (field ht AggBuffers))
      (var num_aggs = (field ht NumAggs))
      (var a i64)
      (= a (: 0 i64))
      (while (< a num_aggs)
        (block
          (var buf = (index agg_buffers a))
          (= buf [size] (: 0 i64))
          (= a (+ a (: 1 i64)))))
      (call agg_apply_reducers agg_buffers size value #t)
      (field_assign ht Size (+ size (: 1 i64)))
      (return size))))
Reset ★★★★★
() автор топика
Последнее исправление: Reset (всего исправлений: 1)
Ответ на: комментарий от Reset

Что это за диалект лиспа/схемы?

Говоришь не осилил. А в КуМире от niisi есть. Получается неплохие спецы его писали? Хотя конечно язык очень странный.

В оригинальном КуМире под советские ЭВМ (Агат кажется первой был) было или нет, интересно?

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 3)
Ответ на: комментарий от Xenius

Я не уверен что в кумире от niisi это есть. Надо проверять. Не в середине идентификатора вносит много неоднозначностей, чтобы это сделать надо понять как точно оно должно работать

Любое дерево можно представить а виде s-expr. Это фактически мой ast в который парсится кумир. Плюс такого представления в том что можно программно работать с ast не думая о синтаксисе.

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

Точно есть, я прорешал на нём весь задачник несколько лет назад. Зачем правда я занимался этой ерундой?.. «если не справа стена» и «если справа не стена» должны быть эквивалентны, вроде понятно?

Надо бы проверить, работает ли это на определенных пользователям функциях и только ли на булевых.

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

Я проверил, работает. Сделано весьма дубово - не в центре идентификаторов просто не поддерживается, поэтому на уровне лексера можно сразу «не» выносить в префикс и генерить два токена.

То есть вот такое

алг нач
кон

алг лог функция не функция
нач
кон

некорректный синтаксис

Reset ★★★★★
() автор топика
Последнее исправление: Reset (всего исправлений: 1)
Ответ на: комментарий от Reset
> алг нач
> кон
> алг лог функция не функция
> нач
> кон

Ты рассчитываешь, что кто-то будет пользоваться твоим жалким поделием? Или тебе заявить о себе во всеуслышание хочется просто?

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

Ты рассчитываешь, что кто-то будет пользоваться твоим жалким поделием? Или тебе заявить о себе во всеуслышание хочется просто?

Знаешь, сколько школьников сдают ОГЭ по информатике? А там есть одно задание, которое можно сделать только на КуМире.

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

P.S. Кстати про браузер правда. На первой странице поиска в инете штук 7 кумиров онлайн и из них только тот что у Reset отработал код.

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 2)
Ответ на: комментарий от Enthusiast

Ты рассчитываешь, что кто-то будет пользоваться твоим жалким поделием? Или тебе заявить о себе во всеуслышание хочется просто?

Им уже пользуются. Кстати у меня единственная реализация которая отлично работает в браузере :)

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

Кстати у меня единственная реализация которая отлично работает в браузере :)

Ну кстати онлайновых кумиров полно. Но первый в списке поиска, например, говорит «ошибка синтакса», а где, какая - не говорит.

Ещё в одном только черепаха. Ещё один не знает слов «использовать» и «алг»

Твой вот такой код отработал, но с недочётом подсветки синтаксиса на слове «всё»:

использовать Робот
алг лестница
нач
	красступ
	если справа свободно то
		вправо
		вниз
	иначе 
		вверх
		вправо
	все
	если снизу стена то
		лестница
	всё
кон

алг красступ
нач
	закрасить
	вправо
	закрасить
кон

Задание из ОГЭ, на поле лестница, робот в начале верхней ступеньки, лестница вначале идёт вниз, потом вверх, ступеньки шириной 2 и высотой 1, количество заранее неизвестно.

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

Ну кстати онлайновых кумиров полно.

Я в курсе. 99% из них просто переписывают синтаксис кумира на регулярках в js. По понятным причинам такой подход нежизнеспособен.

Но первый в списке поиска, например, говорит «ошибка синтакса», а где, какая - не говорит.

Да, это какой-то новый сайт на днях появился. Тоже не работает.

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

А твой кумир умеет распознавать хвостовую рекурсию как в коде выше и не создавать новый стековый фрейм? Впрочем на размере поля, которое физически возможно нарисовать в браузере это наверное непринципиально.

В Tcl есть команда tailcall, можешь добавить аналог, если не хочешь автоматом делать.

Кстати, выход выходит из алгоритма или только из цикла? Для многих задач удобнее возвращать значение раньше отработки всего тела функции - это позволяет сделать код более читаемым, уменьшая количество шагов табуляции на основной программе.

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 3)
Ответ на: комментарий от Xenius

А твой кумир умеет распознавать хвостовую рекурсию как в коде выше и не создавать новый стековый фрейм?

Не умеет

Кстати, выход выходит из алгоритма или только из цикла?

От контекста зависит. Если внутри цикла то из цикла.

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

А не хочешь добавить что-то вроде зови хвост лестница, чтобы результат этого вызова стал результатом текущей подпрограммы, то есть запуск в том же стековом кадре по аналогии с Tcl? Ну или в C и Pascal хвостовой вызов оптимизирует компилятор без подсказок, в fpc начиная с -O2 кажется.

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 5)
Ответ на: комментарий от Reset

А вот ещё вопросик. Ну в вебе всё понятно, прямо в самом же вебе на Canvas и рисует, а на реальном компе он будет рисовать через протокол X11 напрямую, xlib, xcb, sdl, sdl2, sdl3, qt, gtk, fltk, tk или что?

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 1)
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)