Лисп в изгнании
248 subscribers
202 photos
21 videos
5 files
260 links
Авторский канал на околоайтишную тематику.

По всем вопросам @awkravchuk
Download Telegram
#common_lisp

И вот через пару недель работы над Common Lisp'овым фреймворком для паттерна Entity-Component-System есть, чем повыёбываться 😊
Предельно ясный и высокоуровневый код вида

;; определяем компонент "позиция" с вещественными полями x и y
(defcomponent position
(x 0.0 :type single-float)
(y 0.0 :type single-float))

;; определяем аналогичный компонент "скорость"
(defcomponent velocity
(x 0.0 :type single-float)
(y 0.0 :type single-float))

;; определяем систему "движение", которая вычисляет позицию всех сущностей
;; с позицией и скоростью в соответствии с нехитрыми физико-математическими соображениями
(defsystem move
(:components-ro (velocity)
:components-rw (position))
(incf position-x velocity-x)
(incf position-y velocity-y))

после всех нужных притоптываний и приплясываний транслируется замечательным лисповым компилятором SBCL в следующий машинный код (комментарии мои):

disassembly for MOVE-SYSTEMG186
Size: 315 bytes. Origin: #x535A956E
MOV RAX, [R9+45]
TEST BYTE PTR [RAX+1], 1
JEQ L6 ; по метке L6 мы проверяем ещё один бит в [RAX+1]:
L0: MOV [RBP-8], R8 ; если с предыдущего запуска системы к каким-либо сущностям
MOV [RBP-16], R9 ; не добавлялись и не удалялись компонеты, мы обойдём этот
MOV RDI, [R8-7] ; кусок кода и окажемся в метке L1
SUB RSP, 16 ; если же что-то поменялось, будет перестроен и записан на будущее
MOV RDX, R9 ; битовый индекс тех сущностей, которые система должна обходить
MOV RSI, [RIP-302]
MOV ECX, 6
MOV [RSP], RBP
MOV RBP, RSP ; собственно, вот этой функцией и будет перестроен
MOV EAX, #x502EE502 ; #<FDEFN CL-FAST-ECS::%REBUILD-ENTITIES-BITMAP>
CALL RAX
CMOVB RSP, RBX
MOV R9, [RBP-16]
MOV R8, [RBP-8]
MOV RAX, R8
SHR RAX, 10
AND EAX, 1048575
MOV BYTE PTR [R12+RAX], 0
MOV [R8-7], RDX
L1: MOV RSI, [R9+37] ; итак, метка L1: записываем пару вещей в регистры и прыгаем на L4
MOV RDI, [R9+13]
XOR EBX, EBX
JMP L4
NOP
NOP
L2: MOV RCX, [R8-7]
MOV RDX, RBX
SAR RDX, 1
MOV RAX, RDX
SHR RAX, 6
MOV RAX, [RCX+RAX*8+1]
BT RAX, RDX
JB L5
L3: ADD RBX, 2
L4: CMP RBX, RDI ; а на L4 как раз начинается главный цикл системы, который будет
JL L2 ; проходить по всем нужным ей сущностям.
LEA RBX, [RBP+16] ; прыгаем на L2, где делаем два хопа по памяти, чтобы слазить в битовый индекс,
XOR ECX, ECX ; и если понимаем, что нам нужна очередная по номеру сущность, прыгаем на L5
MOV EDX, #x50000117
MOV RDI, RDX
MOV RSI, RDX
STC
MOV RSP, RBP ; если цикл закончился, чистим стек и возвращаемся из функции
POP RBP
RET
L5: MOV RAX, [RSI+1] ; на L5, собственно, и происходят наши сложнейшие вычисления с прибавлением
MOV RCX, [RSI+9] ; к position-x значения velocity-x и то же для y
MOV RDX, [RCX+21] ; подчеркну, что доступ к каждому полю компонента обходится в ещё два хопа по памяти,
MOVSS XMM1, [RDX+RBX*2+1] ; и они последовательные, поэтому аккуратно оседают в кэшах CPU
MOV RCX, [RCX+29]
MOVSS XMM3, [RCX+RBX*2+1]
MOV RCX, [RAX+21]
MOVSS XMM2, [RCX+RBX*2+1]
ADDSS XMM2, XMM1
MOV RCX, [RAX+21]
MOVSS [RCX+RBX*2+1], XMM2
MOV RCX, [RAX+29]
MOVSS XMM1, [RCX+RBX*2+1]
ADDSS XMM1, XMM3
MOV RAX, [RAX+29]
MOVSS [RAX+RBX*2+1], XMM1
JMP L3 ; закончив весь матан, уходим на следующую итерацию цикла по сущностям на L3
L6: TEST BYTE PTR [RAX+1], 2
JEQ L1
JMP L0

Ну камон, 315 байт машинного кода почти без всякого лишнего дроча — это достижение, до которого всяким там обоссанным Unity3D срать и срать 😁
👍4🔥4
#лытдыбр

Вчера на моём курсе по C один из студентов защитил проектную работу, в которой под моим чутким руководством сделал header-only библиотеку для создания замыканий на сишечке, с ручным созданием функции-трамплина в рантайме и с полуавтоматическим управлением памятью. Библиотека, конечно, чистой воды proof-of-concept и не для использования в продакшене, но всё равно требовала для своей реализации кропотливой работы, так что вы знаете, куда насыпать звёздочек ✨
К слову, на днях тут вписался на бесплатный мини-курс по созданию своего интерпретатора лиспа, там подобного рода трюки с замыканиями вполне себе пригодятся. Курс начинается сегодня, так что вы ещё можете успеть тоже вписаться) Для этого нужно написать в личку @IIvana
👍4
#мемасики #common_lisp

По мотивам сегодняшнего стрима 😅
Писать макросы, которые определяют макросы, это каждый раз адский заворот мозговых извилин 🤯
#common_lisp

Меж тем, тихо и незаметно вышла новая версия моего ECS-микрофреймворка для Common Lisp с исправлениями производительности и инкрементальными улучшениями API.

В ближайших планах — чуть больше сместиться в сторону маркетинга и написать про него пару популяризующих статей ☺️
👍6
#репост

Как говорится, вашими бы устами да мёд пить.
Давно уже понял про себя, что мне куда больше по душе проекты-долгострои, нежели проекты с чётко очерченными дедлайнами, хотя дедлайны, конечно, по-своему тонизируют. Примерно как рука, спросонья обожжённая об горячую плиту тонизируют, ага.
❤2👍1
#лытдыбр #common_lisp

Взявшись за написание красивой демки для своей ECS-библиотеки, вот уже во второй раз натыкаюсь на какой-то совершенно адский фундаментальный косяк, который каким-то образом не был выловлен автоматическими тестами. Видимо, придётся сегодня сделать ещё один минорный релиз, а то вдруг Зак наконец разродится новым апдейтом Quicklisp и в нём окажется версия моей библиотеки с багом. Нет слов, как же я на себя зол 😡
🔥2
#репост #common_lisp

Во многом согласен с коллегой по лисповому сообществу, просто не могу не репостнуть 😊
Forwarded from akater
Я выбрал Лисп по нескольким причинам, но в ретроспективе получается, что многие из них вытекают из «Лисп дает своему пользователю максимальную свободу». (Лиспом я называю язык, где есть defun, defmacro, defmethod, unwind-protect, loop, и все это охотно используется.)

Далеко не все языки дают пользователю много свободы. Многие люди предпочитают, чтобы язык ограничивал их (и их коллег — подозреваю, этот момент для многих важнее). Далеко не все считают, что возможность выстрелить себе в ногу — это хорошо.

Лисп старается максимально удалить себя из пространства между его юзером и задачей, которую решает этот юзер. Многие известные его фичи — sexp-синтаксис, макросы, интерактивность, кондишны — как и менее известные ридер-макросы, методокомбинаторы — это лишь следствия этого подхода.

Мне было и есть неприятно программировать не на Лиспе. И по сей день, когда мне нужно написать какое-то сложное условие для if в shell script, я нередко ищу в вебе, какие буквы там писать — и иногда так и не нахожу! Это безумие. В Лиспе с его универсальным (f x y) мне этого никогда не нужно делать, и это было первое, что мне в свое время понравилось в первом языке, на котором мне было приятно программировать (Wolfram Language / Mathematica).

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

Первую свободу дает интерактивность. Можно перекомпилировать отдельную функцию в любой момент, и она становится частью работающей сейчас системы. В Common Lisp нет неизбежной необходимости дублировать выполненные вычисления из-за возникшей в ходе вычисления ошибки, благодаря кондишнам. Состояние программы всегда можно поправить, находясь в самой программе. Я никогда не думаю, что «я пишу код» — я живу в системе, которую расширяю. Это все характеризует интерактивность, недоступную за пределами Лиспа. Помимо интерактивности, в первую свободу делает важный вклад свобода самовыражения.

Не так давно я общался с одним студентом, который активно пишет на Python. Мы обсуждали какой-то его код на Python, и я спросил «почему бы тут не написать switch»? И он сказал «в Python, к сожалению, нет switch». Мне это вновь напомнило, насколько ужасна была бы для меня жизнь как у тех, кто не может себе написать switch, или, скажем, добавить в функции киворды / kwargs по-пайтоновски, если этого нет.

Лисп — это для меня не язык. Это система программирования и способ взаимодействовать с компьютером, разумная альтернатива Юниксу. Я собираюсь так взаимодействовать с компьютером, пока не умру. Сейчас я живу в GNU Emacs, разумеется. Именно Лисп делает это возможным, и альтернатив попросту нет.
🔥6
#common_lisp #лытдыбр

Итак, дёмка моего ECS-фреймворка работает примерно в 5-6 раз медленнее, чем аналогичный код с использованием C-шного фреймворка Flecs. Чего-то подобного я ожидал, но всё равно неприятно. Поверхностный анализ показал, что прорва времени теряется на уровне FFI, при вызове функций для отрисовки из liballegro. Полез разбираться — выяснилось, что в liballegro структура с указанием цвета ALLEGRO_COLOR передаётся во все функции "по значению", т.е. не через указатель, а тупо все поля складываются на стек; а документация к лисповому компилятору SBCL гласит, что "Passing of structures by value is not implemented", поэтому CFFI для передачи этой структуры городит в результирующем коде какой-то адский фарш из дженериков и ручного выделения памяти на куче под эту структуру, я вообще удивлён, что это в 5 раз медленнее, а не во все 50.
Решил для дёмки попробовать какую-нибудь другую графическую либу вместо liballegro, и тут выяснилось, что практически все из них (ну окей, не все, а raylib и SFML), как будто сговорившись, передают структуры с цветом по значению, и только набившая оскомину SDL2 с довольно среднего качества лисповыми биндингами принимает компоненты цвета по-человечески, тупо целочисленными аргументами на стеке, наглядная демонстрация: на SDL выставление цвета отрисовки занимает 153 байта машинных инструкций, вместе с проверкой на ошибки, а на liballegro одно только создание структуры с цветом занимает почти два килобайта (!).
Буду завтра на стриме переписывать дёмку на SDL2, чо 😅
❤5🤪1
#лытдыбр

Выбор ссылки, которая станет превью поста в телеграме — это, блядь, какая-то безвыигрышная лотерея: как ты не ебись, оно сделает так, как не нужно, и это один из немногих косяков, который становится лишь очевиднее после того, как заводишь свой канал. В который раз уже повторюсь, что более косоёбого мессенджера, чем телеграм, я в жизни ни разу не видел, а я настолько мастодонт, что застал ещё ICQ и Miranda. Сколько г-н Дуров вбухал в маркетинг, чтобы все этим костыльным говном пользовались, мне даже примерно представить страшно.
😁1
#лытдыбр #видео

Вчера хвастался своей реализацией самодельного интерпретатора лиспа на сишечьке, сделанной между делом в рамках бесплатного курса. Спасибо Андрею за то, что взял за руку и протащил по этому пути 😁
Упаси меня боже занырнуть в эту сторону с головой и начать писать компилятор своего диалекта лиспа в LLVM-биткод, мне же тогда точно спать станет некогда 😅
🔥3😁1
#common_lisp

Сегодня с утра на стриме с удивлением узнал на опыте, что в SBCL декларация (optimize (space 0)) приводит не к увеличению производительности (хотя казалось бы, если компилятору насрать на всё, включая размер, он потенциально может сделать более большой, но более быстро работающий код), а вовсе наоборот — к деградации скорости работы, причём в моём случае аж в два раза. Век живи — век учись 😅
🔥1
#лытдыбр

Я думаю, это знак, что пора уже расчистить авгиевы конюшни инбокса 😅
#clojure

Минутка бесстыдной рекламы: вот уже в этот четверг, 27 апреля, начнётся первый поток курса Clojure Developer в Otus, к которому ваш покорный немножко приложил руку, и, более того, будет вести в нём несколько занятий. Команда курса собрана очень сильная, поэтому, если всегда хотелось занырнуть в мир разработки на Clojure, добро пожаловать 😊
❤2
#лытдыбр

Хотел тут на этой неделе сделать небольшую паузу и подкопить немного сил перед предстоящим в конце мая Lisp game jam 2023, но жизнь внесла свои коррективы — во вторник на улице шёл град, я закрыл все ставни на балконе, пошёл в магаз, а когда минут через десять вернулся, полбалкона в граде, а в самой квартире (съёмной, на секундочку) всё плавает в воде по щиколотку, хорошо хоть ничего не закоротило, кроме блока питания к ноутбуку. Как мне потом объясняли, град на балкон умудрился попасть каким-то невероятным образом через ливневую канализацию. В итоге вместе с хозяйкой весь день вычёрпывали воду и паниковали по поводу паркета, и до сих пор абсолютно все мышцы в моём теле болят 😭 Такой вот непреднамеренный отдых, лол
🤯1😢1
#лытдыбр #common_lisp #проекты

В рамках подготовки к Lisp game jam возродил тут проект по сборке бинарников SBCL под старые виндусы (включая шиндус 7 — официальный бинарь с sbcl.org работает только под десяткой+). Провозился несколько часов, разобрался с Github Actions и даже зарепортил баг в SBCL — система сборки у него, конечно, заслуживает эпитета "хтонический", но в конечном итоге последняя версия (2.3.4) успешно работает. Забирайте, кому нужно 😊
🔥5
#статьи #common_lisp

Лентой принесло статью про лиспы, которой хотелось бы поделиться. Автор исследует вопрос, что же вообще делает какой-то конкретный язык Lisp'ом; утверждает, что любой акт программирования — это акт создания своего языка, даже когда ты этого не замечаешь, а затем акт его использования (тут на ум сразу приходят шаблоны Django или SQL). Наконец, автор приводит пару примеров из практики на Common Lisp приходит к выводу, что лисп — это любой язык, в котором есть возможность конструировать свои (суб-)языки. Можно спорить о том, насколько часто эта возможность используется (в той же Clojure вроде как многие бестпрактисы отсоветывают писать свои макросы), но в целом со статьёй согласен, лёгкость написания DSL в лиспах — это самая его убойная киллерфича, как мне кажется.
👍1
#clojure #мемасики

Наткнулся тут на великолепный пример использования Clojure 😊
❤4🤔1
#мемасики

В зарубежных интернетах есть такой мемчик, The missile knows where it is, выстёбывающий формалистский текст ради текста (как раз такой, который любит генерировать модный нынче ChatGPT), совершенно шизоидного содержания, типа "ракета знает, где находится, потому что знает, где она не находится". Так вот, на днях наткнулся на ютубе на двухминутный видос с этим текстом, наложенным на демонстрацию кода на JS, и меня чёт вообще порвало 🤣