Pull to refresh

Comments 47

Такие языки как Lisp, Prolog, Forth, Smalltalk думаю и сейчас, возможно, без афиширования используются в тематике ИИ.

Р.S. А, “проиграли” они историческую гонку в силу разных причин и предположу, что их концептуальная простота оказалась мало востребованной в мире развития алгоритмического мышления с проектированием разного синтаксиса языков и перекладыванием на него оформленных задач решаемых семантикой языка. Выражать разнообразную семантику в привязке к синтаксису оказалось в массе своей проще в “Алгол” языках., а IT “художники” остались не у дел.

В рамках Форт (Forth) языка и ИИ, один из проектов в развитии на Github TensorForth https://github.com/chochain/tensorForth (Forth does tensors, in CUDA) - 56 звёзд на текущий момент.

P.S. C Форт такая проблема, что его почти не дают даже в Вузовских программах, не рассматривая школьников (соответственно вокруг его парадигмы не формируется методологический базис) и книги изданные по нему на русском языке в конце 80-х начало 90-х ориентированы на стандарт 83-го года, хотя сейчас в действии ANSI 94-года. Но Форт не забыт и рускоязычными пользователями в действующих форумах, телеграм каналах … и надеюсь увлечёнными “хакерами” :)

При запросе на генерацию кода на нём, думаю, и ИИ подтянут свои скилы, если ещё этого нет и Форт (не путать с Фортран языком!) опять займёт подобающее ему место во всевозможных популярных рейтингах языков программирования.

P.S. А, если появятся кремневые Форт-процессоры (контроллеры), непосредственно поддерживающие Форт, то вообще хорошо. :) (GA144 им в пример https://habr.com/ru/search/?q=GA144)

Какой запрос на генерацию Forth-кода, мужик, ты о чём? Весь сгенерированный LLM-код нужно очень внимательно ревьюить, а ревьюить Forth-код - это такая адская боль, нужно его в голове интерпретировать, удерживая в своей памяти содержимое стека.

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

Отчасти это так, но это относится и к коду и на других используемых языках когда нужно удерживать в памяти логику действий с локальными переменными, которые, ккстати, добавили в стандарт и Форт 94-года.

P.S. А, часто Форт код и нет необходимости читать вне контекста его изменения, при этом достаточно проверить вход/выхход отдельного слова в интерактивном режиме.(в этом аспекте у меня никогда не возникало проблем по “корректировке” Форт кода) К любому коду полученному от той же LLM это также применимо.

Я бы хотел узнать как они работают на низком уровне эти локальные переменные

В целом могут быть варианты реализации (касающиеся, к примеру, Форт- систем с нативной генерацией оптимизированного кода для использования регистров процессора/контроллера как SPF4, VFX Forth, iForth …), но один из вариантов - перенос лок. переменных со стека данных на стек возвратов, если для них не добавили ещё стек локальных переменных.

P.S. Чем интересен Вам Форт язык в сравнении с другими конкатенативными (цепочечными) языками https://concatenative.org (как пример Factor язык включающий и функциональную парадигму)

Почитал каменты, и решил что нам нужен транслятор из Lisp в Forth и компилятор в байт-код для своей виртуальной машины стековой ;)

Почему бы не завести отдельный стек для них?

Так тоже делают, но если “выжимать” из Форт кода при выполнении, к примеру, на регистровых вычислителях (т.к. на масс рынке почему то фактически нет MISC контроллеров/процессоров, если их не реализовывать на FPGA) то теряем в производительности результирующего нативного кода.

P.S. Хотя, вероятно, для Форт понимания это не так важно, если его реализуют и в том числе на языках как Питон и JS, TypeScript (достаточно на Github и др. площадках размещения открытых проектов ввести слово Forth для поисковика). Забавно, что появляются и такие проекты :) https://github.com/ertgl/cx-tagged-template (Class-name expressions in the style of concatenative programming)

Что значит «LISP … из учебников истории»? А AutoCAD?

А, ещё для Autocad была возможность делать скрипты на Форт - Atlast диалект, на Github, помимо оригинального сайта по описанию Atlast находится и такой архив https://github.com/Fourmilab/ClassWar

А в автокаде если я не ошибаюсь основные высокоуровневые возможности лиспа не имплементированы. Там лисп - это просто способ записи кода

Я писал на Common Lisp под AutoCAD в 2008, это было забавно, но больше как макросы чтобы вместо пяти кнопок нажать одну, которая исполняет лисп-код и вот у меня под мышкой нужный мне тип линий для проектирования газопровода. Думаю там потолще функционал был, но всё же автокад это когда человек проектирует, пусть и в эдакой IDE для проектировщиков.

может на AutoLisp? тоже было время мучал его - где то валяется томик Полещука

Скрытый текст

Возможно, почти 20 лет прошло… могу в деталях не помнить.

это были не настоящие макросы. т.е не макросы в стиле лисп, это были макросы в стиле микрософт ворд, т.е хрень.

Есть как есть, зато не в теории по книжке, а на практике для работы использовал.

UFO landed and left these words here

скорее всего он хотел показать как работать через консоль - нам в институте показывали это, на очень старом автокаде. там команды отрисовки примитивов, блоков, всего такого. помню что там координаты абсолютные по умолчанию (хотя конечно внутренние переменные перенастраиваются), а относительные через @. ну и консоль понимает автолисп - так что можно этим пользоваться - подставить выражение вместо чисел - типа (+ 100 200) вернет 300.

Для LLM-ной статьи в целом сойдёт. Остальное придирки.

Маккарти взял из лямбда-исчисления Алонзо Черча нотацию LAMBDA для обозначения функций. Это стало основой синтаксиса Лиспа. Но сам Маккарти позже признавался, что в момент создания языка не очень-то разбирался в лямбда-исчислении - взял нотацию, потому что она казалась удобной и пошел дальше. Позже Дэвид Парк заметил, что рекурсивную LABEL-нотацию можно выразить через конструкцию на LAMBDA, аналогичную Y-оператору Черча. Но сама LAMBDA в Лиспе Y-комбинатором не является.

Lambda сама по себе нигде не является Y-комбинатором, ни в Лиспе, ни в математике. Y-комбинатор составляется из Lambda-выражений, и его смысл в том, чтобы функция вызывала саму себя, не имея имени.

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

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

Условные выражения. if-then-else в том виде, в каком это существует в любом языке - тоже Лисп. Звучит странно, но до 1958-го условные переходы реализовывались как низкоуровневые инструкции, а не как выражения, возвращающие значение.

if и сейчас не в любом языке является выражением.

if и сейчас не в любом языке является выражением.

Знаю только один такой язык: Rust. Ну ещё с натяжкой конструкция conditional expression в Python.

А как насчёт обилия скобок, делавших код многих (большинства?) программистов трудночитаемым? Разве не причина для более поздних времён, когда ни GC ни прочие накладные расходы уже так сильно не влияли на выбор?

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

А как насчёт обилия скобок

Скобки - это наверное лучшее, что есть в лиспе. Трудночитаемость - это миф, да и избыточное количество скобок - тоже (достаточно посмотреть на синтаксис современных языков, типа Rust и C++ - там кроме скобок разного вида ещё и куча закорючек). Этот миф распространяют те, кто никогда на лиспе не писал.

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

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

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

Не во времени, а в общем для всех кодировок диапазоне ASCII, это 128 символов, из которых 34 непечатных (пробел, перенос и табуляцию все же есть чем вводить), а остальные 94 размещаются по 2 на 47 клавишах (33 в "буквенных" рядах, 13 в "цифровом" ну и выбивающаяся более длинная кнопка с бекслешем)

UTF-8 нынче стандарт кодировок и много лет, в принципе клавиатуры уже могут подтягиваться за новыми символами.

Давно уже пора сделать программистскую клавиатуру, где кроме фигурных, угловых, квадратных и обычных будет еще 100500 скобок из уникода и заодно набор символов из APL

Интерполяция строк, блоки, метки, декораторы - всё это позволяет увеличить ёмкость информации и упрощает оперирование.

Скобки лиспа находятся у другой крайности - слишком мало ёмкости.

Категорически нет! Всё ровно противоположно. Лисповые скобки дают бесконечную ёмкость, поскольку позволяют выразить любую глубину абстракции единым и понятным способом. Как раз те костыли, в виде декораторов, меток и пр. - это попытка поднять уровень абстракции средствами, которые для этого не годятся.

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

Я считаю, что об этом стоит написать статью

@" Итого, если в LISP скобка — это базовый эзотерический символ, а в прочих языках соблюдается некий баланс, то в Форте вся эзотерика строится на отсутствии скобок в записи выражений . Мегаследствие: все различия глобальных концептов в программировании определяются числом скобок в языке ! А не всякими там ООП , замыканиями и прочими коротящими мозги штуками ."

https://neolurk.org/wiki/Forth

но получается не принципиально лучше REPL в других языках.

Таки репл в коммонлиспе - это совсем не репл в питоне (и в других языках). Это совершенно разные реплы. Репл в питоне - это интерактивный интерпретатор. Репл в лиспе - это переписывание работающей программы.

Как это возможно, если работающий код в данный момент исполняется?

Грубо - среда, в которой выполняется программа, имеет REPL. Заходите в него, и на ходу правите код. Или, например, крутится у вас web-сервер. Вдруг один из потоков выбрасывает исключение. Вы можете зайти в REPL, поправить код и продолжить выполнение с того места, где возникла ошибка. В других потоках код тоже исправится. Как-то так (грубо).

Про разницу между "интерактивным интерпретатором" и "переписывание работающей программы" я оставлю на совести комментатора, который это ляпнул. Но для повышения всеобщего уровня грамотности на ваш вопрос отвечу.

В C определение функции с именем f означает, что компилятор в пространстве кода сформирует код и символ f, который указывает на этот код и значение которого поменять нельзя. А в Scheme объявление (define f (lambda (x) (+ x 2))) означает, что глобальная переменная f имеет значение-функцию. При вызове функции через имя f, например, так (f 3), будет взято текущее значение этой переменной, а именно значение-функция, определённая лямбдой, и выполнена для переданного аргумента. Значение глобальной переменной можно поменять, и f может начать ссылаться на другую функцию. Когда к f обратятся в следующий раз, то там будет новое значение, но если код из f выполнялся на момент изменения, то он продолжит выполнение до выхода из функции.

REPL - это такое особое Lisp-приложение, в котором поток исполнения в бесконечном цикле читает ввод пользователя, парсит его, выполняет eval для динамического выполнения кода и печатает результат. Поэтому хоть в REPL, хоть не в нём можно поменять значение глобальной переменной с одной функции на другую, пропатчив код. Не у всякого рабочего Lisp-приложения это возможно, обычно для этого приложение, помимо основных рабочих потоков, должно специально оставить REPL-поток, через который можно подключиться и это сделать.

Механизм понят, спасибо!

Кажется, я пару лет назад где-то в комментариях на хабре читал объяснение подобного же механизма у виртуальной машины Эрланга. Поправьте меня, пожалуйста, если я говорю ерунду: я плохо знаком что с Лиспом, что с Эрлангом. Просто хочу узнать, правильно ли я помню, что там тоже можно “править прод на горячую” :)

Как раз на днях допилил свой хот релоад для десктопных и мобильных приложений на своем диалекте лиспа

Почему-то я не вижу статью об этом

В других языках скобок не сильно меньше, просто они расставлены по-другому. Визуально вид лиспового кода может напугать новичка, конечно, но если рельно начинаешь с ним работать, то сразу понимаешь, насколько это удобно. Любой вызов функции, например, это выражение в скобках, где первое это имя (на самом деле не совсем имя, но для простоты можем считать так) функции и остальные элементы -- ее параметры. Например (sin x) -- это аналог sin(x) в C или Питоне (кстати, подсчитайте количество скобок там и тут). А вот сложение нескольких чисел: (+ a b c), аналогом в C будет a+b+c. Да, тут на пару скобок меньше. Зато для сложных выражений надо в памяти держать приоритеты операторов или, омг, тоже добавить скобки. А теперь смотрите -- в Лисп и sin и + это одно и то же, просто вызов функции, работа с ними абсолютно одинакова. Если у вас есть список чисел в переменной x и вы хотите получить их сумму, вы просто пишете: (apply #'+ x) -- подставить список значений x в функцию +, в C или Питоне для этого придется писать цикл. И вот таких трюков в Лиспе множество, многие из них возможны благодаря "скобочному синтаксису".

А теперь о главном, зачем в Лисп скобки. Скобками обозначаются списки, то есть (+ a b c)это просто список из символа + и символов a, b, c. Его можно сформировать программно и выполнить через eval, например. То есть код, сама выполняемая программа, может создаваться "на лету", программно, поскольку это просто список из символов, чисел и других списков. И вот эта концепция "код как данные" делает Лисп на две головы выше остальных языков программирования, позволяет (безопасно и удобно) писать само-модифицирующиеся программы, создавать DSL -- специализированные мини-языки для прикладных задач, да и просто многократно сокращает количество кода, который нужно писать руками, ревьюить и поддерживать. При этом большинство Лиспов это компиляторы, то есть вы можете создать код программно, превратить его в машинные инструкции и вызывать его, прямо на лету, во время исполнения программы.

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

А еще его можно вместо жейсона использовать ;) как ДТО

Смотрю на постер -- и никак не могу развидеть APL

Так как все языки в основе своей используют математические формулы, то можно копнуть ещё глубже аж в 1903 год, когда разработали алгоритм цепи Маркова. Оное больше подходит под язык иИ на базе предсказаний^ ^

Спасибо, отличный разбор. Отдельно понравился разворот в конце про агентов: когда LLM пишет код и тут же гоняет его в живом REPL — это и правда ближе к духу Лиспа, чем к матричному умножению, гомоиконичность почти буквально вернулась. И история про Расселла, который закодил eval вопреки «это нотация для чтения, а не для вычислений» — по сути та же ситуация, что сейчас с агентами: теоретики говорят, что так не должно работать, а кто-то просто берёт и пробует. И иногда работает.

Sign up to leave a comment.

Articles