Веб-версияОткрыть в Telegram
[[TF] Форт и общение фортеров

[TF] Форт и общение фортеров

@ruforth · группа · Технологии · в индексе с 2026-05-28
95участников
30 370сообщений в индексе
В
  1. В
    Не понимаю что значит "системно-зависимым". Не знаю как сейчас работает по скорости lshift по сравнению с умножением, но в старых системах умножение работало медленнее чем lshift.
    1. R
      Зависимость от реализации Форт-системы (see implementation dependent) — зависимость от поведения или функции системы, которые не предписаны стандартом. #forth #terminology
      1. R
        Термином "implementation dependent" (зависящее от реализации) характеризуется функция или поведение, которое должна предоставлять система, но стандарт не определяет, как именно это реализуется, и не требует это документировать. #forth #terminology
    2. В
      : 8* 3 lshift ; : *8 8 * ; : tst1 t6| 2 8* |1t ; seet tst1 : tst2 t6| 2 *8 |1t ; seet tst2 tst1 (10**6 runs) pr: 0 0 T1 = 1212816 tics 0 ms 275 us 640 ns pr: 2 2 Tc = 1221440 tics 0 ms 277 us 600 ns tst2 (10**6 runs) pr: 18 18 T1 = 4118224 tics 0 ms 935 us 960 ns pr: 2 2 Tc = 4084036 tics 0 ms 928 us 190 ns PS. По прежнему сдвиг в разы быстрее.
Вся ветка · 4 ответа →
В
R
R
ruvОдин из подходов — использовать явное или неявное приведение типа (type conversion). Данные, которые приходят извне, имеют тип dyn и не вызывают статической ошибки.
Тут идея в следующем. При чтение значения из памяти, его собственный тип не изменяется. Для слова «@» это можно формально выразить так: ( a-addr[+ x1] -- x1 ) Но, если значение в память попало извне, то для тайпчекера оно имеет лишь самый общий тип x (unspecified cell). И, к примеру, где-то между «read-file» и «@ dup 0<» возникнет статическая несовместимость типов, т.к. в контекст, где ожидается «a-addr[+ n]», передается значение типа «a-addr[+ x]». Оптимистичный или градуальный (gradual typing) тайпчекер может для значений типа x полученных извне (как пример, записанных в память), назначить тип dyn-x, который совместим с любыми подтипами x (или, как вариант, только с подтипами/надтипами u и n). И тогда в примере выше, статически будет передаваться значение типа «a-addr[+ dyn-x]», которое тайпчекер считает совместимым с «a-addr[+ n]». Конечно, этот подход допускает возникновение динамической несовместимости типов при выполнении. Еще, статически можно сужать тип значения (type narrowing) и ловить ситуацию, когда одно и тоже значение интерпретируется по разному в разных местах. В примере выше, тайпчекер может сузить тип значения dyn-x до dyn-n, которое совместимо только с подтипами и надтипами n. И если в другом месте это же значение используется в контексте, где ожидается u или addr, тайпчекер может указать на ошибку. #typesystem #typechecking #gradual
  1. R
    Ссылка
    нажмите — покажем
    В целом, такой код завязан на реализацию Форт-системы и предполагает совместимость бинарных форматов. В данном пример предполагается, что размер ячейки, порядок байт (endianness), и кодирование знаковых целых совпадают в данных извне и в Форт-системе. #forth #abi #compatibility
Вся ветка · 1 ответ →
В
Еще один простой по реализации вариант стековых переменных: \ виртуальное дно стека параметров user-value vds \ преобразование имен m: nalf a[ 1> ] b[ 2> ] c[ 3> ] d[ 4> ] e[ 5> ] f[ 6> ] g[ 7> ] h[ 8> ] ; \ определение определения с установкой виртуального дна стека параметров : s: s0 @ depth 4 * - TO vds : ; \ содержимое ячеек стека начиная от виртуального дна стека параметров m: 1> vds @ ; m: 2> vds 4 - @ ; m: 3> vds 8 - @ ; m: 4> vds 12 - @ ; m: 5> vds 16 - @ ; m: 6> vds 20 - @ ; m: 7> vds 24 - @ ; m: 8> vds 28 - @ ; \ Пример: \ сумма 4-х квадратов чисел : sum_4sqr1 ( n1 n2 n3 n4 -- n.sum ) dup * swap dup * + swap dup * + swap dup * + ; s: sum_4sqr2 ( n1 n2 n3 n4 -- n.sum ) nalf dup * a dup * b dup * c dup * + + + nip nip nip ; : t1 t6| 3 4 5 6 sum_4sqr1 |1t ; : t2 t6| 3 4 5 6 sum_4sqr2 |1t ; seet t1 seet t2 see sum_4sqr1 see sum_4sqr2 : sum_4sqr3 { a b c d } a dup * b dup * c dup * d dup * + + + ; : t3 t6| 3 4 5 6 sum_4sqr3 |1t ; seet t3 see sum_4sqr3 t1 (10**6 runs) pr: 4 4 T1 = 4850208 tics 1 ms 102 us 320 ns pr: 4 4 Tc = 4876696 tics 1 ms 108 us 340 ns t2 (10**0 runs) pr: 4 4 T1 = 4988060 tics 1 ms 133 us 650 ns pr: 0 0 Tc = 5093440 tics 1 ms 157 us 600 ns sum_4sqr1 7D2BAF F7E8 IMUL EAX 7D2BB1 8B5500 MOV EDX , 0 [EBP] 7D2BB4 894500 MOV 0 [EBP] , EAX 7D2BB7 8BC2 MOV EAX , EDX 7D2BB9 F7EA IMUL EDX 7D2BBB 034500 ADD EAX , 0 [EBP] 7D2BBE 8B5504 MOV EDX , 4 [EBP] 7D2BC1 894504 MOV 4 [EBP] , EAX 7D2BC4 8BC2 MOV EAX , EDX 7D2BC6 F7EA IMUL EDX 7D2BC8 034504 ADD EAX , 4 [EBP] 7D2BCB 8B5508 MOV EDX , 8 [EBP] 7D2BCE 894508 MOV 8 [EBP] , EAX 7D2BD1 8BC2 MOV EAX , EDX 7D2BD3 F7EA IMUL EDX 7D2BD5 034508 ADD EAX , 8 [EBP] 7D2BD8 8D6D0C LEA EBP , C [EBP] 7D2BDB C3
  1. В
    Было не предусмотрено доступа к адресам ячеек стека параметров как адресам стековых локальных переменных. Тем самым не было предусмотрено присвоение значений таким локальным переменным(как в ФП). Но форт это не совсем ФП, поэтому присвоение сделать не сложно: m: @1 vds ; m: 1> @1 @ ; и т. д. Подменять имена адресов и содержимого ячеек стека(локалсов) можно произвольным образом. Например адреса можно обозначать большими буквами, b A ! означает записать содержимое второй ячейки от виртуального дна стека параметров в первую ячейку.
    1. R
      Кстати, необходимость в изменении значения локальной переменной возникает только при использовании циклов. В других случаях без этого легко обойтись.
      1. В
        Это точно. 1> 2> + даст возможность использовать сумму (1> 2> +) как 3> без явного присвоения, так как результат сложения содержимого 1 и 2 ячеек будет в ячейке 3 (все промежуточные операции над содержимым стека происходят без потери информации в стеке). В циклах нужно держать количество ячеек стека в определенном диапазоне, поэтому без присвоения (с переустановкой указателя в сторону уменьшения глубины) не обойтись.
      2. R
        А знаете, как эта проблема решается в ФП? Там нету циклов. Только рекурсия. Нет циклов — нет проблемы 😂 Иногда добавляют сахар в виде «for $var in $sequence», где $var принимает значение элементов последовательности (или коллекции), но, формально, это сводится к рекурсии. #functional
        1. В
          Далеко не все алгоритмы хорошо ложатся в рекурсивную схему, поэтому отбрасывать итеративные циклы нецелесообразно.
          1. R
            По идее, эти алгоритмы выражаются через хвостовую рекурсию. А хвостовая рекурсия компилируется в обычный машинный цикл под капотом.
          2. R
            В чистом ФП циклы не удается выразить на уровне семантики (т.е., выразить иначе, чем через рекурсию).
            1. В
              Ну раз в ФП отказались от понятия состояния(которое реально все-таки существует), то конечно нельзя. В форте и состояния есть и рекурсия есть. В конечном итоге вычислительные ресурсы всегда ограничены и при реализации тех или иных алгоритмов требуется это учитывать. Теоретически рекурсия и итерация могут быть преобразованы одна в другую. Есть компиляторы, которые позволяют преобразовать рекурсию в итерацию, чтобы, например ускорить код и/или уменьшить расход памяти.
              1. R
                Ссылка
                нажмите — покажем
                Насчет реальности состояния — это философский и довольно спорный вопрос (см. ранее https://t.me/ruforth/14623/20727). Допустим, у нас есть переход (или отношение): Obj₁ → Obj₂, где Obj₁ и Obj₂ различимы как значения. Что именно позволяет нам сказать, что это изменение состояния одного и того же объекта, а не переход от одного объекта к другому? Насколько сильными должны быть изменения, чтобы мы считали Obj₁ и Obj₂ разными объектами? Содержимое объектов не даёт однозначного ответа. Мы должны ввести функцию идентификации, и если Id(Obj₁) = Id(Obj₂) , то мы интерпретируем этот переход как изменение состояния. И при этом неважно, насколько радикально это изменение. А в ФП мы не столько отказываемся от состояния, сколько отказываемся от интерпретации последовательности состояний (значений) как истории одного и того же объекта. #functional
  2. В
    Ну я не очень понимаю вашу систему. Понял, что регистры. Ну если вложенный вызов процедуры, и еще вызов и ещё много вложенных вызовов.. Вы тестировали такое на быстродействие?
Вся ветка · 10 ответов →
В
Интерпретации должны быть поближе к реальному базису-так оно проще. Триггер имеет два состояния. На этом базируется понятие состояния.
  1. R
    Ну почему же должны? Каждый подход имеет свои сильные и слабые стороны, и ниши, где он предпочтительней другого подхода.
Вся ветка · 1 ответ →

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем