Forth: как это было...

 
+
-
edit
 

Balancer

администратор
★★★★☆
BORS© FORTH мемуары
У меня был интересный этап в развитии нынешнего PHP-фреймворка. В ~1998-м, делая первые сайты, я задумался о шаблонной обработке и упрощении разметки (BBCode родился чуть позже и до России дошёл почти на год позже, Markdown даже в планах не было). Был придуман свой язык разметки, который парсился через QBasic, генерируя уже HTML-код, который и использовался в статических страницах.

Скоро меня запарили проблемы расширения новым функционалом решений на qbasic и я написал парсер на SP-Forth. Написал так, что исходный файл с разметкой без переделки был полноценной программой на Форте :) Вот в таком виде оно полноценно и развернулось.

Уже потом были переход на Perl вместе с выходом в онлайн, перевод платформы на PHP, более 10 лет развития движка… Но прикольно вспоминать, что корни некоторых решений уходят ещё в Forth-прошлое :) // для habrahabr.ru

// Транслировано с juick.com
 

AXT

инженер вольнодумец

Balancer> Уже потом были переход на Perl вместе с выходом в онлайн, перевод платформы на PHP, более 10 лет развития движка… Но прикольно вспоминать, что корни некоторых решений уходят ещё в Forth-прошлое :) // для habrahabr.ru// Транслировано с juick.com

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

unless, кстати да — удачно вписывается в общую идеологию, но байткод придётся хитро генерировать, чтобы сначало всё же проверить условие.
 13.0.782.22013.0.782.220
+
-
edit
 

Balancer

администратор
★★★★☆
AXT> К Форту, кстати, кто-то писал либу, позволяющую базовую арифметику писать инфиксно

Да и я такое писал, благо не сложно.

AXT> там был по факту online преобразователь в код для стековой машины. Ну торомозило, разумеется

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

Просто синтаксис получается сильно смешанный и идеологически неоднозначный.
 38.0.2125.11138.0.2125.111
RU Gudleifr #17.11.2014 16:06  @Balancer#13.11.2014 23:10
+
-
edit
 

Gudleifr

втянувшийся

Balancer> Уже потом были переход на Perl
У меня наоборот: изначальный shell-awk-c-скрипт формирования страниц превратился в Perl-выдергиватель-страниц-из-базы-данных, и только теперь придумал, как к этому без потерь прицепить FORTH-метод: первый план работ. В процессе выяснилось, что в одной из FORTH-машин ячейка стека будет целым текстовым файлом.
 33.033.0
RU Balancer #17.11.2014 16:40  @Gudleifr#17.11.2014 16:06
+
-
edit
 

Balancer

администратор
★★★★☆
Gudleifr> В процессе выяснилось, что в одной из FORTH-машин ячейка стека будет целым текстовым файлом.

Ну, у меня в JBForth в стеке хранились Java-объекты, так что там и файлы могли быть (хотя не использовалось) :) Зато, например, из-за строк как объектов все Форт-слова меняли нотацию в сторону упрощения. Т.е. не ( u addr -- u addr ), а ( String -- String ).
 3838
RU Gudleifr #17.11.2014 16:44  @Balancer#17.11.2014 16:40
+
-
edit
 

Gudleifr

втянувшийся

Balancer>Т.е. не ( u addr -- u addr ), а ( String -- String ).
Я завсегда против ООП, т.е. если "String — String", то речь идет о FORTH-машине, которая ничего окромя "String" и не воспринимает (ну разве что "CtrlString").
 33.033.0
RU Balancer #17.11.2014 17:19  @Gudleifr#17.11.2014 16:44
+
-
edit
 

Balancer

администратор
★★★★☆
Gudleifr> Я завсегда против ООП, т.е. если "String — String", то речь идет о FORTH-машине, которая ничего окромя "String" и не воспринимает (ну разве что "CtrlString").

Оно на JVM работает. И любой Object для JVM — это атомарный элемент. Как int для классического Forth. Работать становится очень удобно.

Кстати, очень хорошо совмещается со сборкой мусора. Скажем, любое Форт-слово — это тоже объект (который при желании можно хранить в стеке). Словарь ищет привязанные Форт-слова и связывает их с использующими их же. Теперь переопределим слово (скажем, исправляем на лету какую-то ошибку). Все новые слова будут использовать переопределённую версию. Старые, пока активны — по-прежнему старую. Пока похоже на классический Форт. Вот только у нас как только отработают все старые слова использующие старый вариант и на них не останется ссылок, пройдёт сборщик мусора и освободит память. Вуаля — мусора не осталось. Можно заниматься разработкой и произвольно обновлять Форт-систему неограниченное число раз прямо на живой системе без её остановки. Получается очень круто. Хоть неделями, месяцами на пролёт система работает, можно писать и переписывать без остановки сервера и без утечек памяти.

Что же касается стека, я в JBForth2 планировал вообще утиную строгую типизацию делать. Ввести на этапе компиляции стек типов и прямо выводить типы вызываемых слов. Это позволило бы компилировать Форт-слова прямо в байткод и иметь полиморфизм.

Но проект так и не стартовал :)
 3838
RU Gudleifr #17.11.2014 17:50  @Balancer#17.11.2014 17:19
+
-
edit
 

Gudleifr

втянувшийся

Balancer> Оно на JVM работает.
А не рассматривался в таком случае вопрос упрощения FORTH-машины в силу наличия уже готовых более мощных механизмов?
Или, наоборот, превращения FORTH-машины в объект, который можно наследовать, суб- и супер-классировать?
 33.033.0
RU Balancer #17.11.2014 18:16  @Gudleifr#17.11.2014 17:50
+
-
edit
 

Balancer

администратор
★★★★☆
Gudleifr> А не рассматривался в таком случае вопрос упрощения FORTH-машины в силу наличия уже готовых более мощных механизмов?

Ну, у меня парсер был не совсем честный :) В смысле не на Форте с BL WORD, а сразу на Java. Что позволило просто и более привычно те же строки вводить, просто описывая их в кавычках ( "Hello world" . ). Или инклудить внешние файлы, просто указав имя и/или относительный путь.

Gudleifr> Или, наоборот, превращения FORTH-машины в объект, который можно наследовать, суб- и супер-классировать?

В Java итак всё — объект. И вся Форт-машина была отдельным объектом. Которых в исходном сервере могло быть несколько. Вообще даже практиковался перезапуск всей Форт-системы просто через присваивание глобальному инстансу нового объекта (а старый потом вычищался сборщиком мусора, когда освобождались все связи).

Вообще, когда JBForth-1 делал, то сперва начинал делать классическую систему, с HERE, addr и т.п. Но быстро понял, что уход от классики делает систему гибче, проще, надёжнее. Скажем, шитый код (в JBF1 он использовался) — это индивидуальный массив в объекте каждого слова, что позволяет не иметь общий код, не ломать голову с FENCE/FORGET и т.п. То есть фактически монолитный байтовый массив оригинальной Форт-машины превращается в графовый набор объектов со взаимными связями, который произвольно модифицируется во время работы.

А выглядел код примерно так в итоге:
code forth
  1. jail: also
  2.  
  3. events diamond arena also
  4.  
  5. forth:: on-player-escape
  6.     jailed? int if
  7.         \ -------- Jail ---------
  8.         "You are jailed yet." "Jail system" player@ .tell
  9.         jail-coords list-rev> drop
  10.     else
  11.         \ -------- Arena --------
  12.         pvp_escape_check
  13.     then
  14. ;
  15.  
  16. previous
  17. previous


Кстати, из Форта, естественно (иначе бы многое потерялось) можно было вызывать произвольные методы настоящих Java-классов, предварительно описав их как Форт-слова:
code forth
  1. 2World.class "getTerritory" { int.class dup } japi-static-func: xy>territory
  2.  
  3. "javolution.util.FastList" class value FastList.class
  4.  
  5. L2Territory.class "getName" { } japi-func: territory>name
  6.  
  7. \ Получить n-й элемент списка:
  8. FastList.class "get" { int.class } japi-func: FastList@
  9. \ Получить размер списка:
  10. FastList.class "size" { } japi-func: FastList#


Массив массивов как один объект в переменной:
code forth
  1. {
  2.     { 122068 -221032 -3674 }
  3.     { 194628 -183403 0571 }
  4.     { -115197 222523 -2948 }
  5.     { 177643 -177243 -544 }
  6.     { 63853 29202 -3841 }
  7.     { 115956 245614 -127 }
  8.     { 83487 147878 -3215 }
  9.     { 79713 146644 -2995 }
  10.     { -109449 220168 -466 }
  11.     { 25885 -148830 -3728 }
  12.     { -10759 -136501 -2576 }
  13.     { 159887 -209841 -3638 }
  14. } value random-points


Ассоциативные массивы (в этом примере индексы целочисленные):
code forth
  1. new-hashmap
  2. { 65897         157895  -3600 1 } => 1
  3. { 52381         153395  -2404 2 } => 2
  4. { 82390         219090  -3482 3 } => 3
  5. { 83373         94298   -3457 4 } => 4
  6. { 109283        84002   -2463 5 } => 5
  7. { 80702         58954   -1968 6 } => 6
  8. { 147461        31418   -2442 7 } => 7
  9. value way-points


Русский иногда использовался по приколу:
code forth
  1. tools.f
  2.  
  3. module: territory:
  4.  
  5. 0 value зона        \ список точек зоны
  6. 0 value точка       \ целое число от 0 до размера зоны - 1
  7. 0 value указатели   \ список npc-указателей границ зоны
  8.  
  9. 1147    constant тип_скилла
  10. 20001   constant тип_моба
  11. 2000    constant задержка
  12.  
  13. : следующая_точка  ( -- )
  14.     точка 1+
  15.     зона list# mod              \ "Заворачиваем" территорию по кольцу
  16.     to точка
  17. ;
  18.  
  19. : предыдущая_точка  ( -- позиция )
  20.     точка
  21.     dup 0 <= if
  22.         зона list# +
  23.     then
  24.     1-
  25. ;
  26.  
  27. : показать_точку  ( -- )
  28.     указатели точка list@ ?dup if false unspawn then
  29.     зона точка list@.
  30.     list-rev> drop z>geo \ получили x y z очередной точки
  31.     0 тип_моба 0 false
  32.     spawn
  33.     dup c.paralyze
  34.     dup указатели точка list!
  35.     указатели предыдущая_точка list@
  36.     ?dup unless
  37.         drop exit
  38.     then
  39.     тип_скилла 1 500 500 new-MagicSkillUser
  40.     player@ p.broadcast
  41. ;
  42.  
  43. : начальная_точка  ( -- )  0 to точка ;


Вообще, сейчас глянул — хотя это был вспомогательный инструмент, тем не менее накатали 1.3Мб в 1580 файлах :)

Balancer / l2fortress / source / data / jbforth — Bitbucket

Need help cloning? Visit Bitbucket 101. Atlassian SourceTree is a free Git and Mercurial client for Windows. Atlassian SourceTree is a free Git and Mercurial client for Mac. Atlassian SourceTree is a free Git and Mercurial client for Windows. Atlassian SourceTree is a free Git and Mercurial client for Mac. // bitbucket.org
 
 3838

AXT

инженер вольнодумец

Balancer> Кстати, очень хорошо совмещается со сборкой мусора. Скажем, любое Форт-слово — это тоже объект (который при желании можно хранить в стеке).

В классической JVM нельзя запихать объект в стек, только ссылку. Ты с C# не путаешь?
 13.0.782.22013.0.782.220
+
-
edit
 

Balancer

администратор
★★★★☆
AXT> В классической JVM нельзя запихать объект в стек, только ссылку.

В Java любая работа с объектами — через ссылки. Потому это подразумевается.
 38.0.2125.11138.0.2125.111
RU Gudleifr #18.11.2014 12:57  @Balancer#17.11.2014 18:16
+
-
edit
 

Gudleifr

втянувшийся

Balancer> В Java итак всё — объект. И вся Форт-машина была отдельным объектом.
Меня прежде всего интересует делился ли этот объект на какие-то смысловые блоки, типа моих 5-и блоков и 4-х источников :)

Требовалась ли рекомбинация/подгонка блоков под конкретную задачу?

Ну, и, конечно, больной для меня вопрос: проявился ли процесс загнивания империализма ООП по мере внедрения FORTH-метода?
 33.033.0
RU Balancer #22.11.2014 13:26  @Gudleifr#18.11.2014 12:57
+
-
edit
 

Balancer

администратор
★★★★☆
Gudleifr> Меня прежде всего интересует делился ли этот объект на какие-то смысловые блоки, типа моих 5-и блоков и 4-х источников :)

Объект по своей сути — штука неделимая, атомарная :)

Gudleifr> Ну, и, конечно, больной для меня вопрос: проявился ли процесс загнивания империализма ООП по мере внедрения FORTH-метода?

Наоборот. Практика использования JBForth показала, что в JBF2 надо делать полноценные объекты, а не процедурную работу с объектами в рамках классического Форта.

В принципе, объекты и в логику Форта укладываются, в общем-то, если рассматривать класс как словарь а методы — как слова из словаря. В принципе, даже можно на словарях реализовать отчасти JVM-совместимую работу. Но это и затратно и не так удобно. Плюс я хотел реализовать компиляцию в полноценный JVM-байткод.
 33.033.0
RU Gudleifr #22.11.2014 15:43  @Balancer#22.11.2014 13:26
+
-
edit
 

Gudleifr

втянувшийся

Balancer> Объект по своей сути — штука неделимая, атомарная :)
В смысле внутренность FORTH не должноа быть видна пользователю или в смысле FORTH реализован поперек ООП и только потом заключен в объект-оболочку?

Balancer> В принципе, объекты и в логику Форта укладываются, в общем-то, если рассматривать класс как словарь а методы — как слова из словаря.
Это не даст использовать ООП по прямому назначению: фреймово-семантическому.
Да, словарь FORTH (как и ассоциативный массив, например, Perl) позволяет легко эмулировать методы классов/объектов. Но для меня это говорит, скорее, об обратном - эти механизмы прекрасно работают и без ООП.

Balancer> В принципе, даже можно на словарях реализовать отчасти JVM-совместимую работу.
На кошачьем форуме коллега mOleg предлагает любой код считать словарем, переопределив "стандартные методы объекта-словаря" так, чтобы FIND выдавал точки входа кода.
 33.033.0
RU Balancer #02.12.2014 01:26  @Gudleifr#22.11.2014 15:43
+
-
edit
 

Balancer

администратор
★★★★☆
Balancer>> Объект по своей сути — штука неделимая, атомарная :)
Gudleifr> В смысле внутренность FORTH не должноа быть видна пользователю или в смысле FORTH реализован поперек ООП и только потом заключен в объект-оболочку?

Форт в терминах JBF — это множество объектов. Но я некорректно высказался. Каждый объект, конечно, не атомарный, может состоять из множества объектов. Я имел в виду именно инкапсулированность, закрытость внутреннего устройства от внешнего непредусмотренного вмешательства.

Gudleifr> Да, словарь FORTH (как и ассоциативный массив, например, Perl) позволяет легко эмулировать методы классов/объектов. Но для меня это говорит, скорее, об обратном - эти механизмы прекрасно работают и без ООП.

Тут вопрос, в первую очередь, не принципиальной возможности работать, а семантического сахара. Это, как раз, в традициях Форта — заменять часто используемую однотипную рутину обобщающей сущность. Скажем, при работе с объектами часто требуется полиморфизм. В Форте его «из коробки» нет, можно делать на словарях, но громоздко. Тогда просто заменяем эту громоздкую работу некой унифицированной — и готово, у нас прилично выглядящий ООП в Форте.

Gudleifr> На кошачьем форуме коллега mOleg предлагает любой код считать словарем, переопределив "стандартные методы объекта-словаря" так, чтобы FIND выдавал точки входа кода.

Как я писал, я отказался от монолитного кода. Я сторонник микрокомпонентного подхода. Так что в каждом высокоуровневом слове — свой бинарный массив шитого кода. Это, как описывал выше, порождает очень высокую гибкость использования сборщика мусора. Можно сколько угодно переопределять слова, отлаживать вживую длительно работающую систему без остановки и т.п.
 39.0.2171.7139.0.2171.71
RU Gudleifr #02.12.2014 10:48  @Balancer#02.12.2014 01:26
+
-
edit
 

Gudleifr

втянувшийся

Balancer> Это, как раз, в традициях Форта — заменять часто используемую однотипную рутину обобщающей сущность.
Опять же, если он и так все это может, зачем тогда ООП?

Спасибо, Ваш подход понял.
Остался только один вопрос: зачем тогда FORTH? Зачем любителю синтаксического сахара столь постный язык? ООП - оно и в Африке ООП, зачем его записывать в FORTH-нотации?
 3.63.6
RU Balancer #02.12.2014 13:21  @Gudleifr#02.12.2014 10:48
+
-
edit
 

Balancer

администратор
★★★★☆
Gudleifr> Опять же, если он и так все это может, зачем тогда ООП?

— Затем, что JVM работает с объектами
— Затем, что сахар.

Gudleifr> Остался только один вопрос: зачем тогда FORTH?

— Forth, благодаря линейному бесскобочному парсеру позволяет очень эффективно и удобно интерпретировать команды с консоли игрового клиента или через telnet.

— Forth позволяет модифицировать/исправлять уже работающую систему прямо из игровой консоли или через telnet.

— Forth позволяет удобно лазить в потроха JVM без предварительной компиляции

— Парсер у Форта очень быстрый и развитую навороченную систему при полной перегрузке скриптовой инфраструктуры грузит за считанные секунды против, например, десятков секунд у аналогичных решений на jython.

— У Форта очень компактный синтаксис, удобный для описания больших блоков данных и т.п.

Думаю, список можно ещё продолжать, это то, что сходу в голову лезет только :)
 3838
RU Balancer #02.12.2014 13:29  @Balancer#02.12.2014 13:21
+
-
edit
 

Balancer

администратор
★★★★☆
А, да, опять же, поточный синтаксис Форта позволяет удобно встраивать Forth-код в HTML- или XML-шаблоны. Т.е. у нас вовсю практиковалось подобное:
code html4strict
  1. <title>Craft statistic (.statcraft)</title><br>
  2. Total items: [ 'SELECT COALESCE(SUM(`count`),0) AS `count` FROM `craftcount` WHERE `char_id` = ' player@ "ObjectId" p@ s+ query drop list> drop 'count' m@ ]
  3. <table width=100%>
  4. <tr><td>Item</td><td>Qty</td><td>Cost</td></tr>
  5. [ craft-stat-html ]
  6. </body>
  7. </html>


То, что в квадратных скобках — произвольный Форт-код, возвращающий String на стеке, который и подставляется потом в HTML.

Или в XML в атрибутах:
code xml
  1.   <skill id="2178" levels="1" name="Blessed Scroll of Escape: Castle">
  2.     <set name="itemConsumeId" val="5859"/>
  3.     <set name="itemConsumeCount" val="1"/>
  4.     <set name="isHandler" val="true"/>
  5.     <set name="target" val="TARGET_SELF"/>
  6.     <set name="skillType" val="CODE"/>
  7.     <set name="code" val="escape_to_castle"/>
  8.     <set name="operateType" val="OP_ACTIVE"/>
  9.     <for>
  10.     </for>
  11.   </skill>


где code — полноценный Форт-код, выполняемый при срабатывании скилла. В примере просто вызов одного слова, но мог быть и длинный код.
 3838
RU Balancer #02.12.2014 13:32  @Balancer#02.12.2014 13:29
+
-
edit
 

Balancer

администратор
★★★★☆
К вопросу о том, зачем ООП. В классическом Форте приходилось писать (пример выше):
code forth
  1. player@ "ObjectId" p@ s+


player@ ( -- L2Player ) — возвращает объект игрока
p@ ( Object String -- Object ) — вызывает метод, имя которого помещается в стеке перед ним.
s+ ( String String -- String ) — сложение строк.

А при реализации ООП можно бы было написать просто:
code text
  1. player.ObjectId +


И это ещё простой пример. В длинных цепочках все эти "method" p@ доставали сильно. И производительность просаживали тоже сильно.
 3838
RU Gudleifr #02.12.2014 14:55  @Balancer#02.12.2014 13:21
+
-
edit
 

Gudleifr

втянувшийся

Balancer> Forth позволяет...
Да, я обычно, рассуждаю так же.
Только, у меня объектно-ориентированность не выходит за рамки реализации FORTH-а.
Например, сейчас "консолью" работает Tcl/Tk, но их объектно-ориентированность наружу, надеюсь, не выйдет.
Когда возникает потребность в структурах (не говоря уже об объектах) обычно все выкидываю и начинаю думать заново.
 3.63.6
+
-
edit
 

digger

опытный

Вопрос чисто от дилетанта.Большинство языков имеют ту же логику ,что и человеческий язык,поэтому учить ,писать и читать на них легко, Forth - наоборот.Можно ли действительно привыкнуть к языкам,настолько далеким от естественного? Чтобы скорость написания и восприятия была такая же,как на С или Питоне.
 34.034.0
+
-
edit
 

Balancer

администратор
★★★★☆
digger> Большинство языков имеют ту же логику ,что и человеческий язык,поэтому учить ,писать и читать на них легко, Forth - наоборот

Сравни:
code text
  1. если (оно_холодное(чайник))
  2. {
  3.     нагреть(чайник)
  4. }


и
code text
  1. ЧАЙНИК ХОЛОДНЫЙ? ЕСЛИ
  2.     ЧАЙНИК НАГРЕТЬ
  3. ТОГДА


Что ближе к естественной логике? :)

digger> Можно ли действительно привыкнуть к языкам,настолько далеким от естественного?

Поверь, «привычные» языки дальше от естественного, чем Форт. Просто ты к ним привык. На Форте можно писать куда естественнее. Чем меньше скобок и спецсимволов, тем ближе к естественному языку. Чем меньше зависимость от структуры, тем, опять же, ближе к языку.

В том же L2F почему я начал Форт использовать, хотя до этого лет 6 к нему не обращался? Потому что потребовалось гибко управлять системой, вводя команды с простого внутриигрового чата. Он годится для того, чтобы писать тексты на естественном языке и (sic!) на Форте. Но отвратительно подходит для ввода программ на Си-подобных языках и вообще непригоден для Python :) В Си-подобных задолбаешься считать скобочки одной строкой, Питон не может работать в однострочном режиме. А на Форте — просто пишешь предложение. Что-нибудь типа
"1000 gold p@.items_add"  do-players.
Это вместо чего-то типа
function give_to_player(player,item_type,amount) { items_add(player, type, amount); } do_all_players(&give_to_player, GOLD, 1000) .
 3838
+
-
edit
 

Gudleifr

втянувшийся

digger> Можно ли действительно привыкнуть к языкам,настолько далеким от естественного?
Коллега Balancer, конечно, прав: FORTH в подавляющем числе отношений ближе к естественным языкам, чем все остальные языки программирования. Но есть более важная вещь. Когда задача сложная, никто не спрашивает программиста, к чему он привык...

digger> Чтобы скорость написания и восприятия была такая же,как на С или Питоне.
Скорость написания и восприятия величина не абсолютная. Она должна быть не просто высокой, а равной скорости писания программиста. Например, по моим оценкам, скорость FORTH примерно равна скорости C (и моей скорости писания), скорость C++ и Python ниже, и они меня раздражают. Скорость Perl - выше, и недокументированные возможности у меня плодятся как кролики.
 3.63.6

AXT

инженер вольнодумец

digger> ...Большинство языков имеют ту же логику ,что и человеческий язык,поэтому учить ,писать и читать на них легко, Forth - наоборот.

Синтаксис японского — Forth, как он есть.
 13.0.782.22013.0.782.220
+
-
edit
 

digger

опытный

Для игр массово используется Lua,в том числе - в консоли,он паскалеподобный.
 34.034.0

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru