<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>АйТи притчи</title><generator>teletype.in</generator><description><![CDATA[Сказ про IT, языки и компиляторы]]></description><link>https://teletype.in/@it_tale?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/it_tale?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/it_tale?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Thu, 09 Apr 2026 19:20:08 GMT</pubDate><lastBuildDate>Thu, 09 Apr 2026 19:20:08 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@it_tale/lisp-format-comma</guid><link>https://teletype.in/@it_tale/lisp-format-comma?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/lisp-format-comma?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Вывод элементов списка через запятую</title><pubDate>Sat, 22 Nov 2025 11:03:18 GMT</pubDate><category>lisp</category><description><![CDATA[Вот регулярно надо, и все время забываю, как это делается.]]></description><content:encoded><![CDATA[
  <p id="CHXa">Вот регулярно надо, и все время забываю, как это делается.</p>
  <p id="8MT0">А просто надо использовать шапку:</p>
  <pre id="8PAe">(format nil &quot;~{~A~^, ~}&quot; (list 1 2 3 ))
&quot;1, 2, 3&quot;</pre>
  <p id="Po6b">Вуаля!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/ai-smells</guid><link>https://teletype.in/@it_tale/ai-smells?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/ai-smells?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>От «творчества» ИИ воняет за километр</title><pubDate>Sun, 24 Aug 2025 02:38:47 GMT</pubDate><description><![CDATA[Копия статьи Игоря Мальцева, vc.ru]]></description><content:encoded><![CDATA[
  <p id="PCN5">Копия статьи Игоря Мальцева, <a href="https://vz.ru/opinions/2025/8/20/1351683.html" target="_blank">vz.ru</a></p>
  <blockquote id="Z2O9">Можно, конечно, сломать ход истории, подойти и плюнуть на картину Малевича, и это тоже будет актом художественного творчества — акционизмом. Но слабая сторона ИИ в том, что он даже этого сделать никогда не сможет.</blockquote>
  <p id="SFaJ">Нам рассказывают про то, как ИИ стремительно идет в территорию вдохновения, в творчество, в частности в изобразительное искусство и музыку.</p>
  <p id="HisZ">У меня плохие новости для верящих в данный маркетологический прогон.</p>
  <p id="9bza">Публика, которая верит в то, что ИИ может создать оригинальное произведение, просто пребывает в иллюзиях, что искусство — бесконечно. Но это просто от незнания, ничего страшного. Хотя нет. Страшновато.</p>
  <p id="yhWX">Как ИИ на выдаче в поисковике паразитирует на том, что собирали и писали живые профессиональные люди на разных ресурсах, таким образом обкрадывая целые издательские дома, точно так же в изо и музыке ИИ тупо паразитирует на всем наследии творческого человечества. А оно — конечно.</p>
  <p id="pw8I">Ведь вы не задумываетесь о том, что музыка имеет очень жесткие законы, в том числе физические и математические, и все они исследованы до последнего герца (440 Hz — нота «ля»).</p>
  <p id="Rofx">Законы квинто-квартового круга, из которого не вырваться. Тон-тон, полутон, три тона-полутон. Кто учил, тот в курсе. Ведь наш гений не зря писал: «поверил алгеброй гармонию». Вариантов гармонических последовательностей настолько мало, что на самые популярные из них, скажем, в интервалах IV–I-II–V, написаны сотни произведений, начиная с «Канона ре мажор» Иоганна Пахельбеля до «Гимна Советского Союза» и Let it Be группы Beatles. Aerosmith с Green Day не упоминать. Четвертая-первая-вторая минор-пятая. Уныло до невозможности. Бесконечные G — D — Em — C. Но есть нюансы.</p>
  <p id="o4GE">Мощный ИИ напишет вам еще тысячу песенок на IV–I-II–V. И он будет собирать мозаику из аранжировок, звучаний, обрывков мелодий, существующих записанных человеческих голосов, безусловно ограниченных тюремными законами гармонии, и создаст еще одну тонну мусора. Две тонны. То есть он делает то, что малоталантливые живые авторы делали все эти годы — строго в соответствии с законами музтеории и музпрактики, плюс мода, плюс конъюнктура, плюс жрать хочется. Просто ИИ может сделать это быстро и много.</p>
  <p id="3HQs">Собственно — последнее «Евровидение» всё звучало, как продукт ИИ. Симпатичная, правильная полная бессмыслица.</p>
  <p id="sy4w">Любой дурак сыграет в подворотне IV–I-II–V в той или иной тональности. Но только у Пола Маккартни получилась Let It Be. А у Александрова — «Союз нерушимый».</p>
  <p id="HozO">По одной простой причине — в рамках строжайших законов ремесла у них есть душа, которая и есть вселенская загадка.</p>
  <p id="Iq1B">А у цифирок с душой напряженка.</p>
  <p id="hYc9">А ведь живые люди уже переступили строгие законы квинто-квартового круга и создали новые — Венская школа с Шенбергом расправилась с законами, по которым писал Моцарт, и открыла врата Густаву Хольсту, а тот — Black Sabbath и так до полной деконструкции и мелодии, и гармонии, но тоже в новых, очень строгих рамках.</p>
  <p id="wf3H">Всё уже написано и записано человечеством. А кого и это не устраивало — тот Карлхайнц Штокхаузен с Джоном Кейджем. Зато на них выросли все «Крафтверки» Германии и вся электронщина мира.</p>
  <p id="2Ja3">И на всем этом тоже вынужден паразитировать бездушный ИИ. Прекрасный пример — недавний хайп стопроцентной ИИ-группы Velvet Sundown на Spotify. Причем только человеку без ушей и без музыкальной памяти непонятно, что это ИИ.</p>
  <p id="SF7z">Как отличить фальшивые надувные шарики? А они точно такие же, только не радуют.</p>
  <p id="XCLn">ИИ заменит, к их сожалению, сотни тысяч неталантливых живых ремесленников, которые лепят песенки по шаблонам, то есть по тем же самым алгоритмам, потому что он делает то же самое только шустрее. Ну и бог с ними.</p>
  <p id="uwhU">Но потом начнется самое интересное: он, ИИ, переварит все то, что сделано людьми, а потом ему придется переваривать уже то, что создано ИИ.</p>
  <p id="Gf3x">И по всем природным законам — продукт пищеварения, еще раз переваренный, остается все той же субстанцией.</p>
  <p id="uIuu">И поэтому так воняет за километр от «художественного творчества» ИИ. Он вынужден переваривать то, что уже придумано людьми за всю историю художественного творчества. А придумано человеком уже буквально всё, что можно изобразить при помощи материалов — осталась одна Марина Абрамович. Да и та скисла, старушка. Провокаторов и без нее хватает.</p>
  <p id="RymU">С каким-то дикарским восторгом в рамках строгого карго-культа неофиты от нейронок ходят буквально под себя, когда им удается получить смешную картинку Йоды в стиле ван Гога. Или «оживить» картину Васнецова. Да, печальный факт — люди знают обычно всего два-три имени и три-четыре стиля и в рамках своих знаний «творят» при помощи нейронок. Насытившись «приколами», начинают генерить портреты шестипалого себя «в стиле».</p>
  <p id="7dbd">И это невозможно видеть глазами. Они кровоточат.</p>
  <p id="Ae3w">Но если размышлять о будущем «недвижущихся картинок», то там произойдет абсолютно то же, что и в музыке «от ИИ».</p>
  <p id="w22q">Дело в том, что уже довольно давно художественное творчество, как совокупность стилей, подходов, материалов, химических составов, пигментов, цвета и формы, давно себя исчерпало.</p>
  <p id="9dUe">Не случайно же есть идиотское выражение, что мы живем в эпоху постомодерна (выпендрялы еще придумывают всякие новые приставки к корню «модерн») — то есть пережевываем по сотому разу всё, что создали предки — начиная с того, который выскребал на стене пещеры бегущих оленей оленьей же костью.</p>
  <p id="rJuj">Придумано всё. Буквально.</p>
  <p id="enOG">Потому что у изобразительного искусства все те же строгие законы. Все цветовые закономерности исследованы до последнего пантона, все формы и антиформы уже создали Ван Дейк с Джексоном Поллоком (и сто тыщ авторов между ними). А искусство еще живо — хотя бы потому, что есть руки, голова и магия материала.</p>
  <p id="sKNA">ИИ лишен рук, материала — красок, кистей или просто ведра для разливания пигмента по холсту, как у Поллока. А фактура, отражение света и даже запах краски — это все составляющие, без которых изображение становится репродукцией в журнале «Огонек».</p>
  <p id="3eAf">А у ИИ — цифра, танец электронов на мониторе. И даже когда ИИ даст мастеру краску и кисть в руки, чтобы поместить картину на поверхность чего-нибудь, то это будет только робот или даже андроид. То есть ходячий принтер. А на принтере мы и сейчас можем безо всякого ИИ слепить что угодно.</p>
  <p id="PDld">И вот точно так же, как люди, которые пережевывают достижения и открытия прошлого, ИИ обречен тупо пережевывать за людьми, а потом будет уже до мышей добираться — то есть извращенцем-Уроборосом жевать свой собственный хвост.</p>
  <p id="zqxC">Потому что все происходит быстро. Очень быстро. В гигантских объемах. И формальное развитие идет очень быстро. Только развиваться некуда.</p>
  <p id="SepM">Ну хорошо, посчитаете себя остроумным, напишете ИИ промпт: «Нарисуй заседание центробанка в стиле Мэн Рэя и Караваджо одновременно». Вау, как смело.</p>
  <p id="DMQf">А потом ведь люди, профессионально занимающиеся, например, историей живописи, обязательно найдут имя и фамилию какого-нибудь деятеля Веймарской республики, который уже придумал это в 1925 году. За что нацисты выгнали его в Америку.</p>
  <p id="jpVw">Потому что было уже всё. Стоило Малевичу намалевать черный квадрат, как обязательно найдется какой-нибудь Марк Ротко, который нарисует черных, красных и синих прямоугольников штук тридцать и будет продаваться за миллионы и висеть в музеях. Не потому, что публика — дура. А потому, что старик Ротко тоже вложил что-то в идиотский черный квадрат. Наверное, это называется «человеческая душа».</p>
  <p id="j3Kr">Можно, конечно, сломать ход истории, подойти и плюнуть на картину Малевича, и это тоже будет актом художественного творчества — акционизмом. Но слабая сторона ИИ в том, что он даже этого сделать не сможет просто никогда. Даже при помощи андроида.</p>
  <p id="kYdd">Зато что касается «картинок движущихся», то по всему интернету бегают новые гуру, которые рассказывают, как при помощи ИИ делать хайповые видео.</p>
  <p id="wJ7x">— А-а-а! — кричат они — Вышла новая версия Reve 1.0 — вы только посмотрите-посмотрите, вы еще быстрее сделаете видео со старухой и бегемотом и порвете видеоплатформы на миллионы просмотров!</p>
  <p id="EmoC">— Или вот! — Новая эра создания видео и игры Genie — всего за 200 долларов подписки! О-о-о!</p>
  <p id="59lf">Причем с таким видом, как будто все приблуды внутри нейронки разработали они лично, а не анонимные индусы из Кремниевой долины. Как шаманы. Помните, как быстро появились «евангелисты» какого-нибудь «Клабхауса» или НФТ — и куда они все делись?</p>
  <p id="cyZP">Так и здесь — восторг от того, что можно вспомнить самую тупую шутку и сгенерить на нее видео с участием модного реального актера из «Марвела». Эта мысль приводит публику в состояние исступления. И публика платит. Надеется порвать интернет и наконец стать хозяином востребованного контента.</p>
  <p id="Fc5y">Срочно бежим на VEO-3! И будет нам счастье и деньги. Завтра выйдет еще пять инструментов, которые для профессиональной работы пригодны так же, как айфон для свадебной фотографии. А со всех сторон несется — «промпт тебе напишет Чат ДжиПи-Ти — даже не надо думать самому, потом заваливаешь в Мидджорни, а потом в ВЕО ТРИ!».</p>
  <p id="3nqz">Дерзай, вперед! Две старухи на самокате! Уморительно смешно! Естественно, стоит увеличить результат «творчества» хотя бы до размеров ноутбучного монитора, то качество картинки посыплется сразу — видно, что это все отвратный ИИ.</p>
  <p id="nHRI">Именно поэтому говорить о какой-то помощи кинематографу невозможно. Оно, конечно, скоро улучшится, но ровно настолько, чтобы никогда не стать профессиональным. Потому что чайник должен сидеть в своей песочнице и время от времени оплачивать подписку за месяц.</p>
  <p id="ox5C">Это как со смартфонами — у всех есть камеры, кругом миллиарды камер, но когда что-нибудь случается — отовсюду нам показывают только мутные видео и бегущие ноги, и даже простые фотки — абсолютно нечитаемые. Даже неподвижный вулкан со столбом пламени внятно снять никто не может. Так и ИИ-видео — только для заработков единиц на очередном «тубе» или тиктоке, пока миллионы чайников платят за подписки на эти инструменты.</p>
  <p id="fBym">Революция отменяется. Без души ничего не работает.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/kensington-expert-mouse-trackball-cursor-freeze</guid><link>https://teletype.in/@it_tale/kensington-expert-mouse-trackball-cursor-freeze?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/kensington-expert-mouse-trackball-cursor-freeze?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Иногда надо чистить даже лазерные мыши и трекболы</title><pubDate>Thu, 15 May 2025 08:59:46 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/55/a9/55a90d96-d087-403e-a7b4-118eac12cc9c.png"></media:content><description><![CDATA[<img src="https://img4.teletype.in/files/7f/03/7f039ef7-3a9e-4a52-972b-9cbb65d12921.png"></img>Век живи, век учись. Сказ о том, что чистить надо не только мозги и рабочее место]]></description><content:encoded><![CDATA[
  <p id="GX1N">Довольно давно я переложил мышку под левую руку, а потом и вовсе заменил ее на трекбол. Вот такой:</p>
  <figure id="K3RG" class="m_column">
    <img src="https://img4.teletype.in/files/7f/03/7f039ef7-3a9e-4a52-972b-9cbb65d12921.png" width="1500" />
  </figure>
  <p id="HRXm">Это Kensington Expert Mouse Trackball. Все в нем замечательно, но со временем появилась проблема — стал останавливаться курсор мыши. Крутишь шар, а мышка на экране не движется. Лечится перетыканием USB разъема.</p>
  <p id="taxg">Честно говоря, думал деградация электроники. При этом я трекбол регулярно чистил, разумеется, но только снаружи.</p>
  <p id="KgEM">Естественно, что я такой был не один. На Reddit&#x27;е народ жалуется, производителю пишут, на Амазон возвращают.</p>
  <p id="iU3L">Производитель даже патч какой-то выпустил, но для моего устройства он не подошел.</p>
  <p id="PMYG">В итоге, случайно, на одном из форумов (они еще живы!) прочитал о том, что у пользователя трекболы этой марки уже больше 15 лет, и что их просто надо эпизодически <em>разбирать</em> и чистить.</p>
  <p id="677y">Я тут же, вооружившись отверткой и любопытством (а что мне терять то, хотел уже другой покупать?) разобрал, продул, протер линзу, прочистил все, до чего смог дотянуться и собрал обратно.</p>
  <p id="eyvz">И, о чудо!, устройство перестало терять курсор. Даже, кажется, быстрее работать стало!</p>
  <p id="qgm5">Так что, как раньше мы чистили механические мышки, а то и спиртом их протирали, так и современные лазерные устройства тоже, оказывается, надо чистить механическим способом.</p>
  <p id="zRFM"></p>
  <p id="cCpG">Век живи, век учись...</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/tail-recursion</guid><link>https://teletype.in/@it_tale/tail-recursion?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/tail-recursion?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Оптимизация хвостовой рекурсии в трансляторе</title><pubDate>Thu, 28 Nov 2024 14:16:54 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/33/df/33dfe90d-5dec-4848-841e-c9d94e70efb1.png"></media:content><description><![CDATA[<img src="https://img1.teletype.in/files/0a/27/0a272035-a2ea-47d9-8b48-03a620352570.png"></img>Копия моей статьи 2018 года о некоторых проблемах реализацииTCO в трансляторах.]]></description><content:encoded><![CDATA[
  <figure id="ayZI" class="m_column">
    <img src="https://img1.teletype.in/files/0a/27/0a272035-a2ea-47d9-8b48-03a620352570.png" width="1250" />
  </figure>
  <blockquote id="Y5TH">Копия моей статьи 2018 года. В принципе, актуальности не потеряла.</blockquote>
  <h2 id="l8Tn">О чем это вообще?</h2>
  <p id="xQ0r">В ежедневной работе программисты, пишущие на императивных языках, нечасто сталкиваются с рекурсивными алгоритмами. Для функциональных же языков рекурсия — естественный способ записи алгоритмов. И пока эти два мира не пересекаются, мало кто задумывается о том, что рекурсия может быть довольно дорогим удовольствием в вычислительном плане. Нет рекурсии — нет проблем.</p>
  <p id="BH3T">Сложности начинаются тогда, когда приходится отображать функциональный подход на императивный. Так, если есть необходимость организовать компиляцию из функционального языка в императивный, например ML в Java или JavaScript.</p>
  <p id="ibfQ">Проблема рекурсивных вызовов в том, что на вызов тратится место в стеке вызовов, т. к. каждый новый рекурсивный вызов, помимо затрат на исполнение тела функции, дополнительно сохраняет точку возврата из текущей функции.<br />А в рекурсивных алгоритмах количество вызовов может быть большим или очень большим. Стек вызовов исчерпывается очень быстро. Частичным решением служит увеличение размера стека вызовов, однако практически это слабо помогает.</p>
  <h2 id="9hL5">Что сложного то?</h2>
  <p id="gd1c">Практический размер стека вызовов редко превосходит несколько тысяч элементов. Это не позволяет делать, например, рекурсивный обход больших бинарный деревьев. И если на императивных языках это можно исправить путем переписывания рекурсивного алгоритма в явно циклический алгоритм (обычно за счет существенного его усложнения), то в функциональных языках избавиться от рекурсии бывает сложно или вообще невозможно.</p>
  <p id="Skcq">Перейдем к <s>кошкам</s> примеру.</p>
  <p id="tVrS">Есть функция <code>for()</code>:</p>
  <pre id="vVFl">// Flow9
for (init, predicate, fn) {
    if (predicate(init))
        for (fn(init), predicate, fn)
    else init
}</pre>
  <p id="DvJL">Транслятор переведет ее в Java или JavaScript один в один, никакой магии (приведен код на Javacript):</p>
  <pre id="suxP" data-lang="javascript">// JavaScript
function for__(init, predicate, fn) {
        if (predicate(init)) {
            return for__(fn(init), predicate, fn);
        } else {
            return init;
        }
    }
}</pre>
  <p id="xVlP">Она даже синтаксически будет выглядеть практически также.</p>
  <p id="REAL">Разумеется, на той же Java эту функцию вполне можно заменить обычным циклом. Но мы же в трансляторе это делаем, нам нужен автоматический перевод, верно?</p>
  <p id="pbzK">Поэтому мы получим рекурсивный вызов. Ну и следом во время выполнения получим исчерпание стека вызовов.</p>
  <h2 id="1DiO">Что делать? Спасите, помогите!</h2>
  <p id="bg59">Чтобы исправить ситуацию и как-то заставить это работать, разработана техника, позволяющая экономить место в стеке вызовов или избавиться от рекурсивных вызовов вообще.</p>
  <p id="PQrH">Мы модифицируем функции таким образом, чтобы изменить рекурсивный вызов на цикл. Это возможно, но, к сожалению, заменить можно не все рекурсивные вызовы. Так, чтобы вызов функции можно было заменить на итерацию цикла, нужно соблюсти несколько условий:</p>
  <ol id="ccsG">
    <li id="kgk3">вызов функции должен быть последним в последовательности операций;</li>
    <li id="c0v0">это должен быть именно рекурсивное обращение к функции, без каких-либо дополнительный операций (например, в вычислении факториала, куда уж без него! , выражение n*fac (n-1) нельзя автоматически заменить на циклический вызов);</li>
    <li id="60HK">вызов функции не может быть вложен в замыкание, т. е. в случае с <code>for()</code> конструкция <code>for(..., \x-&gt;for()..., ...)</code> не будет заменена на циклическую.</li>
  </ol>
  <p id="s4QY">Выполнения этих условий достаточно, чтобы рекурсивный вызов можно было заменить на итерацию цикла. Из-за первого условия (вызов находится в конце последовательности) это явление получило название <a href="https://ru.wikipedia.org/wiki/%D0%A5%D0%B2%D0%BE%D1%81%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F" target="_blank">«хвостовая рекурсия»</a>.</p>
  <p id="JsuE">Решение состоит в том, что мы функцию с хвостовой рекурсией заменяем на цикл, в котором производим манипуляции с аргументами функции так, как если бы мы готовили рекурсивный вызов, а затем передаем управление в начало цикла.</p>
  <p id="Koiu">Есть масса способов это сделать, на просторах Интернета можно найти разные решения.</p>
  <p id="qqED">Я покажу два решения, которые успешно применяются в трансляторах.</p>
  <h3 id="8iQp">Решение первое</h3>
  <p id="SkDc">Функция предварительно готовится с помощью вспомогательной операции:</p>
  <pre id="t3Sa" data-lang="javascript">// JavaScript
function TCO(fn, fn_name) {
    var top_args;
    window[fn_name] = function() {
        var result, old_top_args = top_args;
        top_args = arguments;
        while (top_args !== null) {
            var cur_args = top_args;
            top_args = null;
            result = fn.apply(null, cur_args);
        }
        top_args = old_top_args;
        return result;
    };
    window[&#x27;tc_&#x27; + fn_name] = function() {
        top_args = arguments;
    };
}

TCO((init, predicate, fn) =&gt; {
    if (predicate(init)) {
        return tc_for__(fn(init), predicate, fn);
    } else {
        return init;
    }
}, &#x27;for__&#x27;);</pre>
  <p id="25Q2">Мы запускаем цикл по аргументам функции, вычисляем тело функции, а затем, при необходимости произвести рекурсивный вызов, модифицируем аргументы, с которыми работает тело функции. Модификацией аргументов занимается дополнительная функция, создаваемая в процессе подготовки функции. В приведенном фрагменте это функция, наименование которой начинается с префикса <code>tc_</code></p>
  <p id="cepX">Метод работает безупречно, правда медленно. Виной тому использование метода не самого быстрого метода <code>fn.apply()</code>. В Java используется рефлексия, которая тоже дает падение производительности.</p>
  <p id="j4AZ">Этих недостатков лишен второй метод.</p>
  <h3 id="U8fi">Решение второе</h3>
  <p id="CEQB">Поскольку речь идет о внутренностях транслятора, мы многое знаем о модифицируемой функции. Создадим явный цикл и будем самостоятельно заниматься модификацией аргументов.</p>
  <pre id="rFWF" data-lang="javascript">// JavaScript
function for__(init, predicate, fn) {
    T: while (true) {
        if (predicate(init)) {
            let $a_ = fn(init);
            let $b_ = predicate;
            let $c_ = fn;
            init = $a_;
            predicate = $b_;
            fn = $c_;
            continue T
        } else {
            return init;
        }
    }
}</pre>
  <p id="KRzu">Для каждого аргумента функции, вызываемой рекурсивно, мы создаем дополнительную переменную, а следующим шагом возвращаем значения в аргументы функции. Дополнительный шаг нужен на случай использования аргументов в сложных выражениях.</p>
  <p id="iBuz">Очевидную оптимизацию с неизменяемыми аргументами (см. <code>$b_ = predicate;</code>) оставлю пытливому читателю для самостоятельного изучения.</p>
  <p id="OV5V">Поскольку технически рекурсивный вызов функции отсутствует, этот метод существенно производительнее предыдущего. В большинстве случаев это работает хорошо. Однако мы столкнулись с интересной проблемой, заставившей изрядно поломать голову.</p>
  <h3 id="DAnB">Неожиданная проблема</h3>
  <p id="nbgu">Есть функция, в которой хвостовой рекурсивный вызов параметром получает функцию.</p>
  <p id="aD4u">Модификации аргументов в приведенном методе недостаточно, если в рекурсивный вызов уходит замыкание, использующее аргументы исходной функции.</p>
  <pre id="yyUa">// Flow9
main() {
    recursiveFn(1,  \res -&gt; println(&quot;Внешний вызов. Результат = &quot; + int2str(res)));
}

recursiveFn(counter : int, onOK : (int) -&gt; void) -&gt; void {
        println(&quot;Шапка recursiveFn. Counter = &quot; + int2str(counter));

        if (counter &gt; 1) {
                println(&quot;Первая ветка recursiveFn. Counter = &quot; + int2str(counter));
                onOK(counter)
        } else {
                println(&quot;Вторая ветка recursiveFn. Counter = &quot; + int2str(counter));
                recursiveFn(counter + 1, \newCount -&gt; {
                        println(&quot;Внутренний вызов. newCounter = &quot; + int2str(newCount));
                        onOK(newCount);
                });
        }
}</pre>
  <p id="PKkZ">Ключевой момент — вызов функции <code>onOK</code> после <code>println(&quot;Внутренний вызов. newCounter = &quot; + int2str(newCount))</code>.</p>
  <p id="V9fg">Если мы, что называется, в лоб, преобразуем функцию в JavaScript, результатом будет бесконечная рекурсия.</p>
  <pre id="Iy6d" data-lang="javascript">// JavaScript
function main() {
    return recursiveFn(1, ((res) =&gt; {
        return println((&quot;Внешний вызов. Результат = &quot; + int2str(res)));
    }));
}

function recursiveFn(counter, onOK) {
    T: while (true) {
        println((&quot;Шапка recursiveFn. Counter = &quot; + int2str(counter)));
        if ((counter &gt; 1)) {
            println((&quot;Первая ветка recursiveFn. Counter = &quot; + int2str(counter)));
            return onOK(counter);
        } else {
            println((&quot;Вторая ветка recursiveFn. Counter = &quot; + int2str(counter)));

            let $a_ = ((counter + 1) | 0);
            let $b_ = ((newCount) =&gt; {
                println((&quot;Внутренний вызов. newCounter = &quot; + int2str(newCount)));
                return onOK(newCount);
            });
            counter = $a_;
            onOK = $b_;
            continue T
        }
    }
}</pre>
  <p id="r0Xg">Неважно что будет стоять после строки <code>println((&quot;Внутренний вызов. newCounter = &quot; + int2str(newCount)))</code>, <code>onOK</code> или <code>$b_</code>. Мы получим бесконечную рекурсию из-за того, что замыкание использует внешнее значение функционального параметра <code>onOK</code>.</p>
  <p id="6723">Проблема заключается в том, что замыкание должно оставаться замыканием, т. е. должно захватывать лексическое окружение. Мы же это самое окружение модифицируем для подмены рекурсии циклом. Решение заключается в честной модификации лексического окружения с передачей модифицированных параметров:</p>
  <pre id="grmi" data-lang="javascript">// JavaScript
function main() {
    return recursiveFn(1, ((res) =&gt; {
        return println((&quot;Внешний вызов. Результат = &quot; + int2str(res)));
    }));
}

function recursiveFn(counter, onOK) {
    T: while (true) {
        println((&quot;Шапка recursiveFn. Counter = &quot; + int2str(counter)));
        if ((counter &gt; 1)) {
            println((&quot;Первая ветка recursiveFn. Counter = &quot; + int2str(counter)));
            return onOK(counter);
        } else {
            println((&quot;Вторая ветка recursiveFn. Counter = &quot; + int2str(counter)));

            let $_ta = onOK;
            let $a_ = ((counter + 1) | 0);
            let $b_ = ((newCount) =&gt; {
                println((&quot;Внутренний вызов. newCounter = &quot; + int2str(newCount)));
                return $_ta(newCount);
            });
            counter = $a_;
            onOK = $b_;
            continue T
        }
    }
}</pre>
  <p id="6Z1j">Внимание следует обратить на переменную <code>$_ta</code>, которая уже внутри замыкания используется вместо <code>onOK</code>.</p>
  <p id="RIBB">При трансляции мы модифицируем лексическое окружение для генерации кода замыкания. После генерации тела замыкания лексическое окружение восстанавливается, чтобы не поломать нижележащий код. Это делается тем же способом, что и генерация кода для рабочих серверов (в неотладочном режиме).</p>
  <p id="tLGI">Этот метод трансляции работает корректно и уже используется в боевых системах.</p>
  <h2 id="GBvP">И что, вот так вот и работает?</h2>
  <p id="pxEN">Трансляция хвостовой рекурсии еще споткнулась о ключевые слова. Если посмотреть на определение функции <code>for()</code> выше, то можно увидеть, что в результирующем коде стоит название <code>for__()</code>. Транслятор не видел измененное имя и, соответственно, не помечал его как рекурсивный вызов.</p>
  <p id="wNN9">Не рассмотрены остались некоторые сложные случаи вроде взаимной хвостовой рекурсии, однако для <em>практического использования</em> приведенного решения вполне достаточно.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/Forth</guid><link>https://teletype.in/@it_tale/Forth?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/Forth?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Важные языки. Часть 1. Forth</title><pubDate>Sun, 20 Oct 2024 17:11:29 GMT</pubDate><category>Компиляторы</category><description><![CDATA[4 октября 1957 году Советский Союз запустил в космос первый искусственный спутник земли, а затем 3 ноября 1957 года — второй спутник. Это были события поистине планетарного масштаба! Победа советской научной и технической мысли, результат титанических усилий тысяч ученых и инженеров. Мы по праву гордимся этим достижением и по сей день.]]></description><content:encoded><![CDATA[
  <p id="Itlp">Этой статьей начинаю краткий цикл о трех языках программирования, знакомство с которыми считаю очень важным для любого профессионала в программировании: Форт, Лисп и Оберон.</p>
  <p id="nHKO">Сразу оговорюсь, что я не призываю на этих языках разрабатывать, нужны очень веские причины, чтобы принять такое решение. Но знакомство с ними — важная часть профессионального роста.</p>
  <h2 id="Pw71">Историческая справка</h2>
  <p id="ERdr">4 октября 1957 году Советский Союз запустил в космос первый искусственный спутник земли, а затем 3 ноября 1957 года — второй спутник. Это были события поистине планетарного масштаба! Победа советской научной и технической мысли, результат титанических усилий тысяч ученых и инженеров. Мы по праву гордимся этим достижением и по сей день.</p>
  <p id="S1PG">У конкурирующей же стороны, американцев, еще не было своих спутников (появятся позже), они очень внимательно следили за советскими. Научное сообщество всего мира собирало данные о полете спутников, проводило расчеты и пыталось предсказывать траекторию движения, параллельно подстраивая расчетные методики. Помимо расчета положения спутника (расчета <a href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D0%B5%D0%BC%D0%B5%D1%80%D0%B8%D0%B4%D0%B0" target="_blank">эфемерид</a> и других данных полета), ученые проводили изучение ионосферы Земли, поскольку данные передатчиков, излучающих знаменитое «Бип! Бип!» были известны. На основе наблюдений и расчетов было сделано много научных открытий.</p>
  <p id="1qLk">Занималась этим и Смитсоновская астрофизическая обсерватория, где работал Чарльз Мур, позднее ставший создателем языка Форт.</p>
  <p id="PDpw">Очень любопытным представляется <a href="https://github.com/it-tale/language-history/blob/main/Forth/IGY_Satellite_Report.pdf" target="_blank">отчет</a> с данными наблюдений за спутниками, а также расчетами, пытающихся предсказать место пролета спутников для проведения их фотосъемки. Это несколько томов многостраничных таблиц, перемежающихся небольшими статьями с расчетами тех или иных характеристик полета или окружающей среды.</p>
  <p id="BLge">На странице 30 отчета (страница 175 в PDF) приведена статья «Predictions for Photographic Satellite Tracking Stations — APO Ephemeris 4» за авторством Чарльза Мура (физика-ассистента) и Дона Лаутмана (математика). В этой статье описывается программа Ephemeris 4 для компьютера IBM EDPM 704, предсказывающая положение спутника для использования следящими станциями.</p>
  <p id="LsFK">На трех листах печатного текста дается сухое описание того, что сейчас жаргонно называется «числодробилка», то есть программа из входного массива данных получает другие данные, непосредственно используемые в экспериментах и практической работе.</p>
  <p id="WRfJ">Как позже сам Мур напишет в статье <a href="https://github.com/it-tale/language-history/blob/main/Forth/The%20Evolution%20of%20Forth.pdf" target="_blank">The Evolution of Forth</a>, чтобы избежать постоянной перекомпиляции исходных текстов программы, он реализовал простой интерпретатор, читающий входные данные с карт. Это позволило компоновать уравнения для разных спутников без повторной компиляции.</p>
  <p id="ip97">Интерпретатор предоставлял несколько команд и концепций, перекочевавших в современные реализации Форта. Использовалась команда чтения «слов», разделенных пробелами, команда преобразования чисел из внешнего во внутреннее представление (<em>по всей видимости имеется ввиду лексический разбор — прим. авт.</em>), а также конструкт <code>IF ... ELSE ...</code>.</p>
  <p id="b5Tu">Мур обнаружил, что свободное форматирование кода может быть и более эффективным (код меньше и производительнее), и более надежным в сравнении с распространенным в то время колоночным расположением кода на Фортране.</p>
  <p id="tI4C">После завершения учебы Мур в работе использовал разные языки программирования: ALGOL, JOVIAL, PL/I, FORTRAN и всевозможные ассемблеры, не оставляя, тем не менее, идеи использования интерпретатора, который он «таскал с собой, буквально нося пачку перфокарт» (<em>прямая цитата — прим. авт.</em>)</p>
  <p id="1HGp">Из языков программирования Мур заимствовал идеи в свой интерпретатор, реализуя с его помощью все более сложные программы. Так появились кросс-ассемблер, примитивный редактор и система управления исходниками. Кроме того, он создал программу для генерации анимированных 3D изображений и шахматную программу, а также игру <em>Spacewar</em>. В интерпретатор добавился стек значений, переменные, арифметические операции и операции сравнения, возможность задания процедур.</p>
  <p id="yMA8">В это время появляется название FORTH. Оно отсылает к четвертому поколению компьютеров, как тогда называли маленькие компьютеры. Буквой U из слова FOURTH (четвертый) пришлось пожертвовать из-за того, что файловые системы того времени не позволяли использовать имена файлов длиной более 5 символов. Написание Forth (без капитализации) появилось значительно позже, опять же благодаря файловым системам, способным различать строчные и заглавные буквы.</p>
  <p id="dky1">Важной вехой стало появление «словаря». Это отдельная сущность, в которую помещались имена процедур вместе с указателем на код, который их реализует. Фактически это была реализация «<a href="https://ru.wikipedia.org/wiki/%D0%A8%D0%B8%D1%82%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4#%D0%9A%D0%BE%D1%81%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D1%88%D0%B8%D1%82%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4" target="_blank">косвенного шитого кода</a>», осуществленная за 5 лет до появления этого <a href="https://github.com/it-tale/language-history/blob/main/Forth/Indirect%20threaded%20code.pdf" target="_blank">термина</a>.</p>
  <p id="hbYd">Наконец, последней концепцией, дополнившей картину Форта стала идея отдельного «стека возвратов», упростившего использование данных и процедур, без необходимости балансировать стек до/после вызова процедуры.</p>
  <h2 id="tTb9">Философия Мура</h2>
  <p id="Rypk">Для Мура Форт был личным ответом на разочарование от современного ему программного обеспечения, которое он называл «Вавилонской башней»:</p>
  <blockquote id="0h27">The software provided with large computers supplies a hierarchy of languages: the assembler defines the language for describing the compiler and supervisor; the supervisor the language for job control; the compiler the language for application programs; the application program the language for its input. The user may not know, or know of, all these languages: but they are there. They stand between him and his computer, imposing their restrictions on what he can do and what it will cost. <br /><br />And cost it does, for this vast hierarchy of languages requires a huge investment of man and machine time to produce, and an equally large effort to maintain. The cost of documenting these programs and of reading the documentation is enormous. And after all this effort the programs are still full of bugs, awkward to use and satisfying to no one.</blockquote>
  <p id="SFLM">Вольный перевод:</p>
  <blockquote id="Rh4V">ПО, предоставляемое с большими компьютерами привносит иерархию языков: ассемблер определяет язык для описания компилятора и супервизора; супервизор — языки для управления заданиями; компилятор — язык для приложений; приложения — входной язык для данных. Пользователь может не знать все языки или знать не все языки, но они присутствуют. Языки находятся между пользователем и его компьютером, выставляя собственные ограничения того, что можно делать и ожидаему стоимость решения.<br /><br />И эта стоимость обширной иерархии языков требует огромных вложений времени человека и машины для создания, равно как и огромных усилий по поддержанию работоспособности. Огромна и стоимость документирования и изучения документации этих программ. В конечном итоге программы все-равно полны ошибок, неудобны в использовании и никому не нравятся.</blockquote>
  <p id="hLqZ">С религиозной настойчивостью Мур отстаивал принцип «Keep it simple!», считая его «Основополагающим принципом». Не без оснований он считал, что для многих задач Форта достаточно. </p>
  <p id="UGiB">С этим можно спорить, но Мур был последователен в отстаивании своих принципов. Он реализовал Форт для 18 разных ЦПУ, писал весь требуемый инструментарий, включая кросс-ассемблеры, драйверы и т.д.</p>
  <p id="dTZx">Мур был очень требователен к ПО, которое он разрабатывал. Многократно перерабатывая и улучшая Форт, он добивался того, что система выполняла требуемые функции, оставаясь при этом маленькой, эффективной и гибкой.<br />Гибкость Форта вместе с его интерпретируемой природой показали огромную эффективность и впечатляющие результаты во многих приложениях.</p>
  <h2 id="u14G">Важность Форта</h2>
  <p id="humm">Форт очень простой язык, и ценность его для программиста состоит в том, что он позволяет практически дотронуться до нескольких концепций, лежащих в его основе.</p>
  <h3 id="lGuT">Интерпретация</h3>
  <p id="VssJ">Код на Форте интерпретируется. Каждое «слово» на языке исполняется либо кодом внутри интерпретатора, либо комбинацией других «слов». Понимание этого механизма позволяет лучше разбираться в системах, которые используют подобные техники. Так, то, что сейчас называется intrinsic в виртуальных машинах или в других системах, где есть сколь-нибудь сложный рантайм, корнями уходят в том числе в Форт.</p>
  <h3 id="Wr7X">Стек значений</h3>
  <p id="66mz">Использование стека для значений выражений с непривычки может показаться неудобным. Однако, подобная структура данных позволяет очень компактно и элегантно реализовывать весьма непростые вещи. Кроме того, алгоритмы для работы со стеком очень легко генерировать. Поэтому нередко виртуальные машины для высокоуровневых языков реализуются именно как <a href="https://habr.com/ru/companies/intel/articles/254793/" target="_blank">стековые машины</a>.</p>
  <h3 id="nmUt">Словари</h3>
  <p id="hIim">Структура, отображающая имя в какую-то другую сущность, сегодня, кажется, проникла во все языки программирования в том или ином виде, однако, в Форте она имеет особое значение. Словарь является более высокоуровневой сущностью, по сравнению со «словом». Он может быть наделен своей семантикой и в программе может быть разное количество словарей.</p>
  <h3 id="bt2O">Простота реализации</h3>
  <p id="9rCk">Интерпретатор Форт можно реализовать за один-два вечера. Причем это будет полноценная реализация.</p>
  <h2 id="58cD">Современные реализации</h2>
  <p id="xpoZ">Сегодня сам по себе Форт используется нечасто. Однако идеи этого языка и того, как он реализован используются очень много.</p>
  <p id="sScl">Так, PDF и PostScript — это прямые потомки языка Форт. Во FreeBSD с версии 3.1 до версии 12 в загрузчике использовался интерпретатор Forth (позже заменен на Lua). Уже упомянутые стековые виртуальные машины используют идеи Форта.</p>
  <p id="fKAY">TON Blockchain внутри использует Форт-подобный язык и стековую машину.</p>
  <p id="srcW">Не могу не упомянуть российскую разработку — <a href="https://github.com/rufig/spf" target="_blank">SP-Forth</a> и разработку российского разработчика по рождению Славы Пестова <a href="https://factorcode.org/" target="_blank">Factor</a>.</p>
  <p id="uxVQ">Надеюсь, эта информация поможет расширить ваш программный инструментарий!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/svg-drawing-3</guid><link>https://teletype.in/@it_tale/svg-drawing-3?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/svg-drawing-3?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Чертежи в SVG формате. Часть 3 — Черновик стандарта</title><pubDate>Wed, 05 Jun 2024 11:21:11 GMT</pubDate><description><![CDATA[<img src="https://img2.teletype.in/files/12/27/1227f37d-61ba-4a8e-96e5-aa0b38719897.png"></img>В &quot;Чертежи в SVG формате. Часть 2 — Черновик стандарта&quot; приведён пример рисование простых графических объектов из CAD систем. В продолжении рассмотрим рисование штриховки для разных материалов.]]></description><content:encoded><![CDATA[
  <p id="IbBI">В &quot;Чертежи в SVG формате. Часть 2 — Черновик стандарта&quot; приведён пример рисование простых графических объектов из CAD систем. В продолжении рассмотрим рисование штриховки для разных материалов.</p>
  <h3 id="Kk4Z">Штриховка</h3>
  <p id="PzkZ">Шаблон штриховки рисуем в <code>defs</code> части чертежа используя тег <code>pattern</code>.<br />Шаблон для штриховки металла (тип <code>0</code>) под углом <code>45°</code>.</p>
  <pre id="QyIX">&lt;pattern id=&quot;hatch0_45&quot; width=&quot;20&quot; height=&quot;20&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;1&quot; y1=&quot;20&quot; x2=&quot;20&quot; y2=&quot;1&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;0&quot; y1=&quot;1&quot; x2=&quot;1&quot; y2=&quot;0&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="TJab">Многие заметят и зададут вопрос, зачем нарисовано две линии вместо одной с координатами <code>x1=&quot;0&quot; y1=&quot;20&quot; x2=&quot;20&quot; y2=&quot;0&quot;</code>?<br />Пример штриховки с одной линией в шаблоне</p>
  <figure id="tIQU" class="m_original">
    <img src="https://img2.teletype.in/files/12/27/1227f37d-61ba-4a8e-96e5-aa0b38719897.png" width="337" />
  </figure>
  <p id="GeV9">если внимательно присмотреться то увидим разрывы в линии штриховки.<br />Пример штриховки с двумя линиями в шаблоне</p>
  <figure id="gMtX" class="m_original">
    <img src="https://img4.teletype.in/files/fb/b5/fbb5b282-345d-4931-9110-f414c260edb2.png" width="342" />
  </figure>
  <p id="khtc">с двумя линиями таких разрывов нет.</p>
  <p id="kjsV">Фрагмент кода области заштрихованной типом металл под углом <code>45°</code>.</p>
  <pre id="N5IK">&lt;path d=&quot;M475,225 L475,325 L500,325 L500,225 Z&quot; fill=&quot;url(#hatch0_45)&quot;/&gt;</pre>
  <p id="jsEx">Шаблон для штриховки металла (тип <code>0</code>) под углом <code>30°</code>:</p>
  <figure id="AOSX" class="m_original">
    <img src="https://img1.teletype.in/files/8c/52/8c52fd36-9533-4dec-965e-31664c0399a3.png" width="391" />
  </figure>
  <pre id="96GH">&lt;pattern id=&quot;hatch0_30&quot; width=&quot;34&quot; height=&quot;20&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;2&quot; y1=&quot;20&quot; x2=&quot;34&quot; y2=&quot;1&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;-1&quot; y1=&quot;2&quot; x2=&quot;3&quot; y2=&quot;-1&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="ZIMZ">Примеры штриховки других материалов:</p>
  <figure id="4EIN" class="m_original">
    <img src="https://img2.teletype.in/files/98/13/98133a30-bda8-43cf-96f3-96f1e8ba4d14.png" width="359" />
  </figure>
  <p id="V7eb">Шаблон для штриховки неметалла (тип <code>1</code>) под углом <code>45°</code>:</p>
  <pre id="3z1E">&lt;pattern id=&quot;hatch1_45&quot; width=&quot;34&quot; height=&quot;20&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025 &quot; x1=&quot;0&quot; y1=&quot;20&quot; x2=&quot;20&quot; y2=&quot;0&quot; /&gt;
    &lt;line class=&quot;line-type-2_025 &quot; x1=&quot;0&quot; y1=&quot;0&quot; x2=&quot;20&quot; y2=&quot;20&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="dtfU">Шаблон для штриховки дерева (тип <code>2</code>), в таком варианте для каждой области штриховки необходимо создавать свой шаблон. Пока другого варианта не придумал, как нарисовать окружности и габарит шаблона больше от области заштриховывания. Может кто-то удачнее решение придумает.</p>
  <pre id="ef8M">&lt;pattern id=&quot;hatch2_45&quot; width=&quot;350&quot; height=&quot;350&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;180&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;200&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;220&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;240&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;260&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;280&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;300&quot; fill=&quot;none&quot;/&gt;
    &lt;circle class=&quot;line-type-2_025&quot; cx=&quot;0&quot; cy=&quot;0&quot; r=&quot;320&quot; fill=&quot;none&quot;/&gt;    
&lt;/pattern&gt;</pre>
  <p id="CdLS">Шаблон для штриховки камня естественного (тип 3) под углом 45°</p>
  <pre id="TxqC">&lt;pattern id=&quot;hatch3_45&quot; width=&quot;20&quot; height=&quot;20&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025 &quot; x1=&quot;0&quot; y1=&quot;20&quot; x2=&quot;12&quot; y2=&quot;8&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="b0BV">Шаблон для штриховки керамики (тип 4) под углом 45°</p>
  <pre id="iv1u">&lt;pattern id=&quot;hatch4_45&quot; width=&quot;20&quot; height=&quot;20&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;0&quot; y1=&quot;16&quot; x2=&quot;16&quot; y2=&quot;0&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;4&quot; y1=&quot;20&quot; x2=&quot;20&quot; y2=&quot;4&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;0&quot; y1=&quot;4&quot; x2=&quot;4&quot; y2=&quot;0&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;16&quot; y1=&quot;20&quot; x2=&quot;20&quot; y2=&quot;16&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="7xLS">Шаблон для штриховки бетона (тип 5) под углом 45°</p>
  <pre id="fkN5">&lt;pattern id=&quot;hatch5_45&quot; width=&quot;20&quot; height=&quot;20&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;0&quot; y1=&quot;30&quot; x2=&quot;6&quot; y2=&quot;24&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;10&quot; y1=&quot;20&quot; x2=&quot;26&quot; y2=&quot;4&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="QBpt">Шаблон для штриховки стекла (тип 6) под углом 45°</p>
  <pre id="nlMr">&lt;pattern id=&quot;hatch6_45&quot; width=&quot;30&quot; height=&quot;30&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;5&quot; y1=&quot;15&quot; x2=&quot;13&quot; y2=&quot;7&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;5&quot; y1=&quot;25&quot; x2=&quot;25&quot; y2=&quot;5&quot; /&gt;
    &lt;line class=&quot;line-type-2_025&quot; x1=&quot;17&quot; y1=&quot;23&quot; x2=&quot;25&quot; y2=&quot;15&quot; /&gt;
&lt;/pattern&gt;</pre>
  <p id="22rW">В случаи когда необходимо в заштрихованной области иметь не заштрихованную можно применить такое решение.</p>
  <pre id="rOwn">&lt;path class=&quot;line-type-2&quot; d=&quot;M0,575L0,600 15,675 100,650 250,675 300,575z&quot;/&gt;
&lt;path d=&quot;M0,575L0,600 15,675 100,650 250,675 300,575z&quot; fill=&quot;url(#hatch0_45)&quot;/&gt;
&lt;circle class=&quot;line-type-2&quot; cx=&quot;150&quot; cy=&quot;625&quot; r=&quot;40&quot;/&gt;
&lt;circle cx=&quot;150&quot; cy=&quot;625&quot; r=&quot;40&quot; fill=&quot;white&quot;/&gt;</pre>
  <p id="fZFe">Область окружности накладывается на заштрихованную область.</p>
  <figure id="kj6d" class="m_original">
    <img src="https://img3.teletype.in/files/61/b3/61b3b767-2a48-46d5-b3a1-071d8c0431fa.png" width="208" />
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/svg-drawing-2</guid><link>https://teletype.in/@it_tale/svg-drawing-2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/svg-drawing-2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Чертежи в SVG формате. Часть 2 — Черновик стандарта</title><pubDate>Thu, 30 May 2024 12:07:41 GMT</pubDate><description><![CDATA[<img src="https://img2.teletype.in/files/5f/48/5f48160a-7c85-45f3-93a8-e6c5a7cf7efd.png"></img>Рассмотрим рисование простых графических объектов из CAD систем.]]></description><content:encoded><![CDATA[
  <p id="IiWo">В &quot;<a href="https://teletype.in/@it_tale/svg-drawing-1" target="_blank">Чертежи в SVG формате. Часть 1 — Черновик стандарта</a>&quot; приведён пример объектной модели чертежа, задания масштаба и стилей линий. В продолжении рассмотрим рисование простых графических объектов из CAD систем.</p>
  <h2 id="00pU"><strong>Простые графические объекты</strong></h2>
  <p id="FAen">В CAD системах используются следующие простые графические объекты:</p>
  <h3 id="1syM"><strong>Точка</strong> (маркер)</h3>
  <figure id="Vc6x" class="m_original">
    <img src="https://img2.teletype.in/files/5f/48/5f48160a-7c85-45f3-93a8-e6c5a7cf7efd.png" width="413" />
  </figure>
  <p id="NxkN">Шаблон и стили отображения точки мы рисуем в <strong>defs</strong> части чертежа.</p>
  <pre id="ez08">&lt;marker id=&quot;Point0&quot; viewBox=&quot;-10 -10 20 20&quot; markerWidth=&quot;5&quot; markerHeight=&quot;5&quot;&gt;
  &lt;path d=&quot;M-3,0 L0,-3 3,0 0,3 z&quot; stroke=&quot;red&quot; fill=&quot;none&quot;/&gt;
&lt;/marker&gt;</pre>
  <p id="xnsk">Выводим точку в чертеже с помощью тега <strong>path</strong>. В свойстве <strong>stroke-width</strong> задаём обратный масштаб вида, если масштаб вида <code>1:4</code>, то для точки указываем масштаб <code>4:1</code>.</p>
  <pre id="07qW">&lt;path stroke-width=&quot;4&quot; d=&quot;M50,35&quot; marker-end=&quot;url(#Point0)&quot;/&gt;</pre>
  <h3 id="kZSs">Линия</h3>
  <figure id="yzDm" class="m_original">
    <img src="https://img3.teletype.in/files/e2/4e/e24e83e6-057a-49fb-ac2f-aaa14c2ca04d.png" width="263" />
  </figure>
  <p id="NOES">В CSS файле описываем типы линий.</p>
  <pre id="GGj3">line, rect, circle, ellipse, path, text {
  vector-effect: non-scaling-stroke;
}
/* основная */
.line-type-1 {
  fill: none;
  stroke: blue;
  stroke-width: 2;
}
/* тонкая */
.line-type-2 {
  fill: none;
  stroke: black;
  stroke-width: .7;
}
/* осевая */
.line-type-3 {
  fill: none;
  stroke: red;
  stroke-width: .7;
  stroke-dasharray: 25, 4, 3, 4;
}
/* штриховая */
.line-type-4 {
  fill: none;
  stroke: black;
  stroke-width: .7;
  stroke-dasharray: 7, 4;
}
...</pre>
  <p id="vhof">А в чертеже используем тег <strong>line</strong> с присваиванием ему класса типа линии.</p>
  <pre id="7YAI">&lt;line class=&quot;line-type-1&quot; x1=&quot;0&quot; y1=&quot;0&quot; x2=&quot;500&quot; y2=&quot;0&quot;/&gt;</pre>
  <p id="S1Lu">Для тега <strong>line</strong> задано свойство <em><code>vector-effect</code></em> с значением <strong><code>non-scaling-stroke</code></strong>. В любом заданном масштабе для вида линии будут отрисовываться с одинаковой толщиной.</p>
  <h3 id="lTXX">Окружность</h3>
  <figure id="ncc0" class="m_original">
    <img src="https://img3.teletype.in/files/22/de/22de36b0-7904-4108-9cfd-98c4060ea75d.png" width="243" />
  </figure>
  <p id="XOBK">Типы линий используем как и для тега <strong>line</strong> из CSS файла.<br />А в чертеже используем тег <strong>circle</strong> с присваиванием ему класса типа линии.</p>
  <pre id="c8pF">&lt;circle class=&quot;line-type-1&quot; cx=&quot;165&quot; cy=&quot;25&quot; r=&quot;125&quot;/&gt;</pre>
  <h3 id="AOaa">Эллипс</h3>
  <figure id="kbfV" class="m_original">
    <img src="https://img4.teletype.in/files/77/3b/773b8105-6a67-4ff2-a39d-0748484654fc.png" width="110" />
  </figure>
  <p id="Ukuz">Типы линий используем как и для тега <strong>line</strong> из CSS файла.<br />А в чертеже используем тег <strong>ellipse</strong> с присваиванием ему класса типа линии.</p>
  <pre id="d2u6">&lt;ellipse class=&quot;line-type-3&quot; cx=&quot;120&quot; cy=&quot;280&quot; rx=&quot;100&quot; ry=&quot;50&quot;/&gt;</pre>
  <h3 id="rv5p"><strong>Дуга и дуга эллипса</strong></h3>
  <figure id="CX12" class="m_original">
    <img src="https://web.archive.org/web/20230607233050im_/http://habrastorage.org/storage2/5c5/0ea/c69/5c50eac6989662ea50bec077ff357867.png" width="142" />
  </figure>
  <p id="xuu1">Типы линий используем как и для тега <strong>line</strong> из CSS файла.<br />А в чертеже используем тег <strong>path</strong> с присвоением ему класса типа линии. В свойстве <strong>d</strong> задаём параметры дуги.</p>
  <pre id="ErTb">&lt;path class=&quot;line-type-2&quot; d=&quot;M50,50 A140,140 0 0 1 200,350&quot;/&gt;	
&lt;path class=&quot;line-type-3&quot; d=&quot;M20,150 A20,40 0 0 1 130,50&quot;/&gt;</pre>
  <h3 id="eE9u"><strong>Прямоугольник</strong></h3>
  <figure id="48Wn" class="m_original">
    <img src="https://web.archive.org/web/20230607233050im_/http://habrastorage.org/storage2/104/1e6/9d1/1041e69d17be4cccadd325c6473eb1b8.png" width="115" />
  </figure>
  <p id="rN4q">Типы линий используем как и для тега <strong>line</strong> из CSS файла.<br />А в чертеже используем тег <strong>rect</strong> с присвоением ему класса типа линии.</p>
  <pre id="XXsW">&lt;rect class=&quot;line-type-1&quot; x=&quot;20&quot; y=&quot;5&quot; width=&quot;395&quot; height=&quot;287&quot;/&gt;</pre>
  <h3 id="HQ3H"><strong>Ломаная линия</strong></h3>
  <figure id="DTYD" class="m_original">
    <img src="https://web.archive.org/web/20230607233050im_/http://habrastorage.org/storage2/6ab/458/0b6/6ab4580b6747edd24943e898c85a5c1b.png" width="104" />
  </figure>
  <p id="4ZwE">Типы линий используем как и для тега <strong>line</strong> из CSS файла.<br />А в чертеже используем тег <strong>polyline</strong> с присвоением ему класса типа линии.</p>
  <pre id="f8LJ">&lt;polyline class=&quot;line-type-7&quot; points=&quot;20,250 50,250 60,300 80,120 120,140 200,180&quot;/&gt;</pre>
  <h3 id="KqGz"><strong>Кривая NURBS (сплайн)</strong></h3>
  <figure id="CmKN" class="m_original">
    <img src="https://web.archive.org/web/20230607233050im_/http://habrastorage.org/storage2/297/dc7/d76/297dc7d761cb43c3a7e01e7d932bcb8f.png" width="128" />
  </figure>
  <p id="gt6J">Типы линий используем как и для тега <strong>line</strong> из CSS файла.<br />А в чертеже используем тег <strong>path</strong> с присвоением ему класса типа линии.</p>
  <pre id="Yre0">&lt;path class=&quot;line-type-2&quot; d=&quot;M140,201.34 C144.696,186.7859 152.303,175.3664 162.822,167.0820
    C167.996,163.0066 174.363,158.9944 180.459,157.132
    C194.3626,152.8843 213.0561,157.132 225.5589,167.082
    C232.5067,172.6114 241.8569,177.1221 250,177.9937
    C263.3438,179.4220 275.9399,163.2633 290.0,160
    C299.5142,157.7918 310.4253,154.6301 319.5409,157.132
    C325.7604,158.8390 332.0035,163.0066 337.1780,167.082
    C347.6966,175.3664 353.3294,189.206 360,201.3405&quot;/&gt;</pre>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/svg-drawing-1</guid><link>https://teletype.in/@it_tale/svg-drawing-1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/svg-drawing-1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Чертежи в SVG формате. Часть 1 — Черновик стандарта</title><pubDate>Thu, 30 May 2024 10:22:03 GMT</pubDate><description><![CDATA[Мопед не мой, я только объявление разместил (с)]]></description><content:encoded><![CDATA[
  <blockquote id="w0j0" data-align="right"><em>Мопед не мой, я только объявление разместил (с)</em></blockquote>
  <p id="KRnd" data-align="right">Это цикл статей, посвященных работе с SVG, размещенный на сайте <a href="http://v.sytnik.lviv.ua" target="_blank">http://v.sytnik.lviv.ua</a> (ныне недоступный). Статьи мне показались очень информативными, поэтому захотелось их сохранить.</p>
  <p id="woOT">В интернете можно найти много разной информации о создании чертежей в формате SVG. Чаще предлагается какой-то редактор и экспорт из формата DXF в SVG. Просматривая код SVG сразу видно что там много лишнего. Созданный в одном редакторе файл SVG не всегда может корректно открыться в другом. Одно радует, что браузеры начали поддерживать SVG формат. Всюду пишут про недостатки использования SVG. А может надо придерживаться единых правил структуры файла для отображения чертежей?</p>
  <p id="uDvB">Из экспериментов и тестов пришёл к таким правилам при создании чертёжа:</p>
  <ul id="rynw">
    <li id="9Rr3">использование объектной модели чертежа;</li>
    <li id="NvCO">используем только одну единицу измерения (та что по умолчанию в пикселях);</li>
    <li id="KzsQ">условно принимаем — один пиксель равен одному миллиметру (для браузера будет в <code>пикселях</code>, а для нас в <code>мм</code>);</li>
    <li id="gjcW">масштаб описания элементов всегда <code>1:1</code>;</li>
    <li id="urWQ"> для отображения объектов в другом масштабе используем вложенный <em>svg</em> рисунок;</li>
    <li id="VXM4">для уникальных объектов задаём <code>id</code> а для характерных <code>class</code>;</li>
    <li id="IfhT">…</li>
  </ul>
  <h2 id="43ix"><strong>Объектная модель чертежа</strong></h2>
  <p id="XQRO">Упрощенно чертёж можно описать в виде XML структуры.</p>
  <pre id="c0AF" data-lang="svg">&lt;svg id=&quot;Detail1&quot; ...&gt;
    &lt;defs id=&quot;defsCAD&quot;&gt; ... &lt;/defs&gt;
    &lt;svg id=&quot;Shtamp&quot; name=&quot;Frame drawing&quot; ... &gt;
        ...
    &lt;/svg&gt;
    &lt;svg id=&quot;View1&quot; ... &gt;
        &lt;g id=&quot;layer-0&quot; name=&quot;System layer&quot; ...&gt;
            &lt;line class=&quot;line-type-1&quot; ... /&gt;
            &lt;line class=&quot;line-type-1&quot; ... /&gt;
            &lt;circle class=&quot;line-type-1&quot; ... /&gt;
            &lt;path class=&quot;line-type-1&quot; ... /&gt;
            &lt;rect class=&quot;line-type-1&quot; ... /&gt;
            &lt;line class=&quot;line-type-2&quot; ... /&gt;
            &lt;line class=&quot;line-type-2&quot; ... /&gt;
            &lt;g class=&quot;dimL&quot;&gt;
                &lt;line class=&quot;line-type-2&quot; ... /&gt;
                &lt;line class=&quot;line-type-2&quot; ... /&gt;
                &lt;line class=&quot;line-type-2&quot; ... /&gt;
                &lt;text ... &gt;...&lt;/text&gt; 
            &lt;/g&gt;
            ...
        &lt;/g&gt;
        &lt;g id=&quot;layer-1&quot; name=&quot;Layer 1&quot; ...&gt;
            ...
        &lt;/g&gt;
    &lt;/svg&gt;
    &lt;svg id=&quot;View2&quot; ... &gt;
        &lt;line class=&quot;line-type-1&quot; ... /&gt;
        ...
    &lt;/svg&gt;
    &lt;svg id=&quot;View3&quot; ... &gt; ... &lt;/svg&gt;
&lt;/svg&gt;</pre>
  <h3 id="PeQD">Тег svg</h3>
  <p id="2ZdY">&lt;<strong>svg</strong>&gt; — тег используется для описания самого чертежа и встроенных видов, штампа и техтребований. Если необходимо использовать масштаб отличный от <code>1:1</code>, то реализуется с помощью свойств тега.<br />Например масштаб <code>1:4</code></p>
  <pre id="PnJk" data-lang="svg">&lt;svg id=&quot;View1&quot;
     x=&quot;50&quot;
     y=&quot;7&quot;
     width=&quot;150&quot;
     height=&quot;162&quot;
     viewBox=&quot;-25 -200 600 648&quot;&gt;</pre>
  <p id="IoK4">width=&quot;<strong>150&quot;</strong> height=&quot;<strong>162&quot;</strong> viewBox=&quot;…… <strong>600</strong> <strong>648</strong>&quot; — соотношение величин задаёт масштаб отображения вида на листе.</p>
  <p id="Ao8c">Например масштаб 10:1</p>
  <pre id="uwus" data-lang="svg">&lt;svg id=&quot;View1&quot; 
     x=&quot;50&quot; 
     y=&quot;7&quot; 
     width=&quot;150&quot; 
     height=&quot;162&quot; 
     viewBox=&quot;-0.6 -5 15 16.2&quot;&gt;</pre>
  <h3 id="TqlY">Тег defs</h3>
  <p id="v72Y">&lt;<strong>defs</strong>&gt; — здесь описываем все примитивные повторяющиеся элементы. Замечена одна особенность при использовании SVG элемента <code>marker</code> — на него не действуют параметры масштаба из тега &lt;<strong>svg</strong>&gt;, что намного упрощает работу с масштабом. (При любом масштабе вида стрелки в размерах должны быть одинаковые). Но на линии в элемента <code>marker</code> не действует параметр свойства <em><code>vector-effect: non-scaling-stroke</code>;</em></p>
  <h3 id="XVJq">Тег line</h3>
  <p id="HBc4">&lt;<strong>line class=</strong>«atr1» …/&gt; — в файле CSS описываем стили линий для графических примитивов. Жаль что в Internet Explorer для каждого масштаба необходимо указывать свой стиль линии (толщина линии и интервал пунктиров). Как правило в чертеже одновременно не используются все возможные масштабы и достаточно задать только для используемых масштабов.<br />Пример описания стилей линий для элементов <code>line</code>, <code>circle</code>, <code>path</code>, <code>rect</code> и др.:</p>
  <pre id="3EpY" data-lang="css">line, rect, circle, ellipse, path, text {
  vector-effect: non-scaling-stroke;
}
/* main line */
.line-type-1 { fill: none; stroke: blue; stroke-width: 2;
}
/* hairline */
.line-type-2 { fill: none; stroke: black; stroke-width: .7;
}
/* axial */
.line-type-3 { fill: none; stroke: red; stroke-width: .7; stroke-dasharray: 25, 4, 3, 4;
}
/* dashed */
.line-type-4 { fill: none; stroke: black; stroke-width: .7; stroke-dasharray: 7, 4;
}
/* main line for the scale 0.25 */
.line-type-1_025 { fill: none; stroke: blue; stroke-width: 8;
}
/* hairline for the scale 0.25 */
.line-type-2_025 { stroke: black; stroke-width: 2.8;
}</pre>
  <h3 id="K4fN">Тег g</h3>
  <p id="NQEE">&lt;<strong>g</strong> class=&quot;dimL&quot;&gt;…&lt;/<strong>g</strong>&gt; — элементы описывающие объекты как размер группируем.<br />Пример:</p>
  <pre id="EOKt" data-lang="svg">...
&lt;defs id=&quot;defsCAD&quot;&gt;
&lt;!-- Draw arrows and tick marks --&gt;
    &lt;marker id=&quot;dimArrow-1&quot; viewBox=&quot;-2 -12 29 24&quot; markerWidth=&quot;44&quot; markerHeight=&quot;36&quot; orient=&quot;auto&quot;&gt;
        &lt;path class=&quot;line-type-2_025&quot; stroke=&quot;black&quot; d=&quot;M0,0 L20,-4 16,0 20,4 z M0,-10 L0,10 M0,0 L27,0&quot;/&gt;
    &lt;/marker&gt;
    &lt;marker id=&quot;dimArrow-2&quot; viewBox=&quot;-27 -12 29 24&quot; markerWidth=&quot;44&quot; markerHeight=&quot;36&quot; orient=&quot;auto&quot;&gt;
        &lt;path class=&quot;line-type-2_025&quot; stroke=&quot;black&quot; d=&quot;M0,0 L-20,-4 -16,0 -20,4 z M0,-10 L0,10 M0,0 L-27,0&quot;/&gt;
    &lt;/marker&gt;
&lt;/defs&gt;
...
    &lt;g class=&quot;DimL&quot;&gt;
        &lt;line class=&quot;line-type-2&quot; x1=&quot;190&quot; y1=&quot;180&quot; x2=&quot;190&quot; y2=&quot;230&quot;/&gt;
        &lt;line class=&quot;line-type-2&quot; x1=&quot;310&quot; y1=&quot;180&quot; x2=&quot;310&quot; y2=&quot;230&quot;/&gt;
        &lt;line id=&quot;dim1&quot; class=&quot;line-type-2&quot; x1=&quot;190&quot; y1=&quot;230&quot; x2=&quot;310&quot; y2=&quot;230&quot; marker-start=&quot;url(#dimArrow-1)&quot; marker-end=&quot;url(#dimArrow-2)&quot;/&gt;
        &lt;text x=&quot;265&quot; y=&quot;222&quot; font-size=&quot;28&quot; text-anchor=&quot;middle&quot;&gt;120&lt;/text&gt; 
    &lt;/g&gt;
...</pre>
  <p id="guQ5"></p>
  <p id="tEcV">Есть одна особенность отображения графики в SVG. Если мы задали область и хотим по краю её нарисовать контур, то должны отступить на пол толщины линии иначе линии будут на половину тоньше. Например кода чёрной рамочки края чертежа.</p>
  <pre id="uZbt" data-lang="svg">&lt;svg id=&quot;Shtamp&quot; type=&quot;1&quot; x=&quot;0&quot; y=&quot;0&quot; width=&quot;420&quot; height=&quot;297&quot; viewBox=&quot;0 0 420 297&quot;&gt;
    ...
    &lt;rect class=&quot;line-type-2&quot; x=&quot;1&quot; y=&quot;1&quot; width=&quot;418&quot; height=&quot;295&quot;/&gt;
   ....
&lt;/svg&gt;</pre>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/rotate-svg-world</guid><link>https://teletype.in/@it_tale/rotate-svg-world?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/rotate-svg-world?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Дайте мне точку опоры...</title><pubDate>Fri, 17 May 2024 10:31:59 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/04/24/042455b5-67a8-4d0a-a540-5e12abebc77f.png"></media:content><category>lisp</category><description><![CDATA[<img src="https://img3.teletype.in/files/a2/99/a29947b1-7cf5-4473-8903-35d183df61f8.jpeg"></img>...и я переверну землю. Заметка о том, как перевернуть мир в отдельно взятом SVG файле (на Lisp).]]></description><content:encoded><![CDATA[
  <p id="uw2T">...и я переверну землю.</p>
  <figure id="QYCy" class="m_column">
    <img src="https://img3.teletype.in/files/a2/99/a29947b1-7cf5-4473-8903-35d183df61f8.jpeg" width="1600" />
    <figcaption> Котик переворачивает землю. <a href="https://www.yaplakal.com/forum13/st/0/topic283452.html" target="_blank">ЯПлакал</a></figcaption>
  </figure>
  <p id="18WZ">Эту фразу приписывают Архимеду, так, во всяком случае, нам говорили в школе.</p>
  <p id="5sIT">Иногда действительно требуется перевернуть мир, пусть и несколько в ином смысле.</p>
  <h3 id="JXqF">Координатная система SVG</h3>
  <p id="bQLj">Понадобилось мне сохранить векторный рисунок. Для этого SVG подходит как нельзя лучше — генерируется просто, размер небольшой, структура понятна и предсказуема.</p>
  <p id="MB1u">Вот только незадача, координата Y в нем идет не так, как принято в математике — привычная нам ось идет вверх, тогда как в SVG — вниз. Пробуем рисовать. Будем использовать библиотеку <a href="https://github.com/wmannis/cl-svg" target="_blank">cl-svg</a>.</p>
  <blockquote id="wPqk">В Quicklisp устаревшая версия, поэтому имеет смысл склонировать ее себе в ~/quicklisp/local-projects/ и выполнить <code>(ql:register-local-projects)</code>.</blockquote>
  <p id="n3Yc">Итак, делаем простейший файл, рисуем координатные оси, ну или их какое-то подобие.</p>
  <pre id="3ujX">(in-package #:svg)

(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)
  
  (draw scene (:line :x1   0 :y1 -10 :x2   0 :y2 200))
  
  (draw scene (:line :x1 -10 :y1   0 :x2 200 :y2   0)))</pre>
  <p id="7Uyg">Запускаем, получился файл <code>coord.svg</code>. Запускаем его и... ничего.</p>
  <p id="jBPx">Правильно, потому что по стандарту линия не рисуется, если у нее не задано значение цвета пера (<code>stroke</code>). Кроме того, у нас не задано значение поля <code>viewPort</code>.</p>
  <p id="v0wF">Корректный вариант такой (далее первую форму <code>(in-package #:svg)</code> опускаю):</p>
  <pre id="yd8U">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel
	   :height 230
	   :width 230
	   :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)

  (draw scene
      (:rect :x -20 :y -20 :height 230 :width 230)
      :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;)
  
  (draw scene
      (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)
  
  (draw scene 
      (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;))</pre>
  <p id="eP1W">Линии осей нарисованы зеленым цветом.</p>
  <p id="fRbx">Для удобства восприятия добавлен прямоугольник под картинку.</p>
  <p id="KgjE">Получилось что-то такое:</p>
  <figure id="bERQ" class="m_retina">
    <img src="https://img3.teletype.in/files/a8/8a/a88ac6f3-c468-4f28-a6da-c962d4e7e885.png" width="230" />
  </figure>
  <p id="ijkz">Как мы видим, ось Y растет вниз.</p>
  <p id="v4Ya">Для того, чтобы перевернуть ось, можно просто нарисовать ось X снизу, а остальные расчеты просто вести с поправкой на то, что координаты перевернуты. Решение вполне себе нормальное, но придется внести изменения в расчетную часть, а они могут быть нетривиальными и не всегда просто реализуемыми. Кроме того, наверняка появится множество краевых случаев, которые нужно будет обрабатывать.</p>
  <p id="5W7W">Попробуем другой метод.</p>
  <h3 id="55xd">Использование CSS</h3>
  <p id="wBiB">SVG позволяет использовать стилевую информацию. Этим мы и воспользуемся.</p>
  <p id="aeFX">Добавим стиль, применяющий масштаб <code>-1</code> к тегу <code>&lt;svg&gt;</code>:</p>
  <pre id="AAv7">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230 :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)
  
  (style scene &quot;svg#toplevel {display:flex; transform: scaleY(-1);}&quot;)
  
  (draw scene
      (:rect :x -20 :y -20 :height 230 :width 230)
      :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;)
  
  (draw scene
      (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)
  
  (draw scene
      (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;))</pre>
  <p id="tu3i">Идентификатор <code>#toplevel</code> создается внутри класса <code>svg-1.1-toplevel</code>.</p>
  <p id="OlzC">Получилась замечательная картинка:</p>
  <figure id="MmMt" class="m_retina">
    <img src="https://img2.teletype.in/files/d0/cb/d0cbafb4-16ee-492f-919a-c0ddebff8870.png" width="230" />
  </figure>
  <p id="lDQL">Прекрасно, давайте развивать решение. Добавим текста:</p>
  <pre id="Wbho">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230 :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)

  (style scene &quot;svg#toplevel {display:flex; transform: scaleY(-1);}&quot;)

  (draw scene
      (:rect :x -20 :y -20 :height 230 :width 230)
      :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;)

  (draw scene
      (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)

  (draw scene
      (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;)

  (text scene (:x 20 :y 20) &quot;Привет!&quot;))</pre>
  <figure id="cs0P" class="m_retina">
    <img src="https://img3.teletype.in/files/aa/ad/aaad5dc3-b8af-4215-9ef8-de0e546aad88.png" width="230" />
  </figure>
  <p id="KvkT">Ооочень интересно. Перевернут не только мир, но и текст.</p>
  <p id="gQMz">Это забавно, но логично.</p>
  <p id="OH3c">Хорошо, давайте теперь применим масштабирование и к тексту:</p>
  <pre id="fZym">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230 :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)

  (style scene &quot;svg#toplevel {display:flex; transform: scaleY(-1);}&quot;)

  (style scene &quot;svg#toplevel &gt; text {transform: scaleY(-1);}&quot;)

  (draw scene
      (:rect :x -20 :y -20 :height 230 :width 230)
      :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;)

  (draw scene
      (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)

  (draw scene
      (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;)

  (text scene (:x 20 :y 20) &quot;Привет!&quot;))</pre>
  <p id="786d">Текст перевернулся, но теперь он расположен непонятно где:</p>
  <figure id="XPnE" class="m_retina">
    <img src="https://img1.teletype.in/files/0d/b8/0db8f64c-0a20-4421-b623-c77493a240a9.png" width="230" />
  </figure>
  <p id="lmey">Все дело в том, что преобразование <code>scaleY(-1)</code> выполняется относительно начала координат, а не относительно координат элемента, к которому это преобразование применяется. Получается, что базовая линия шрифта находится на координате Y, равной 20, и после применения масштабирования расположено также на 20 пикселей от оси, но в другую сторону.</p>
  <p id="EL8k">Можно применить дополнительные преобразования — сначала перенести текст к началу координат, затем масштабировать, затем отнести снова назад. Но это нужно рассчитывать, давайте сделаем по-другому.</p>
  <p id="UXWy">Обернем текст в группу и потом применим преобразование к тексту.</p>
  <pre id="1SIY">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230 :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)

  (style scene &quot;svg#toplevel {display:flex; transform: scaleY(-1);}&quot;)

  (style scene &quot;svg#toplevel g &gt; text {transform: scaleY(-1);}&quot;)

  (draw scene
      (:rect :x -20 :y -20 :height 230 :width 230)
      :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;)

  (draw scene
      (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)

  (draw scene
      (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;)

  (make-group scene
      (:transform &quot;translate(20, 20)&quot;)
    (text*  (:x 0 :y 0) &quot;Привет!&quot;)))</pre>
  <figure id="Q3ov" class="m_retina">
    <img src="https://img4.teletype.in/files/32/9e/329e9272-51be-4791-8470-1bc528d03779.png" width="230" />
  </figure>
  <p id="RoxK">Получилось то, что нужно!</p>
  <p id="YdLM">Ключевым здесь являются вызовы </p>
  <pre id="eJyh">(style scene &quot;svg#toplevel g &gt; text {transform: scaleY(-1);}&quot;)

...

(make-group scene
      (:transform &quot;translate(20, 20)&quot;)
    (text*  (:x 0 :y 0) &quot;Привет!&quot;))</pre>
  <p id="e6cu">У тега <code>&lt;g&gt;</code> нет своих координат <code>x</code> и <code>y</code>, но к нему можно применить преобразование  <code>transform()</code>, и в нем задать нужное смещение. Кроме того, координаты <code>x</code> и <code>y</code> для текста можно не указывать, но библиотека <code>cl-svg</code> требует, чтобы они были указаны, поэтому вписываем.</p>
  <h3 id="0vqu">Вложенные группы</h3>
  <p id="hcRR">Как частное решение это вполне сойдет. Но для более сложного документа лучше будет сгруппировать элементы логически. Это сделает документ структурированным и более удобным в ряде случаев, например при работе в консоли браузера.</p>
  <pre id="Kd95">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230 :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)

  (style scene &quot;svg#toplevel {display:flex; transform: scaleY(-1);}&quot;)

  (style scene &quot;svg#toplevel g &gt; text {transform: scaleY(-1);}&quot;)

  (make-group scene (:id &quot;frame&quot;)
    (draw*
     (:rect :x -20 :y -20 :height 230 :width 230)
     :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;))

  (make-group scene (:id &quot;axes&quot;)
    (draw*
     (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)
    (draw*
     (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;))

  (let ((texts (make-group scene (:id &quot;texts&quot;))))
    (make-group texts (:transform &quot;translate(20, 20)&quot;)
      (text*  (:x 0 :y 0) &quot;Привет&quot;))
    (make-group texts (:transform &quot;translate(30, 40)&quot;)
      (text*  (:x 0 :y 0) &quot;Мир&quot;))
    (make-group texts (:transform &quot;translate(30, 60) rotate(90)&quot;)
      (text*  (:x 0 :y 0) &quot;SVG&quot;))))</pre>
  <p id="hRyV">В последнем случае дополнительно текст повернут на 90 градусов, то есть можно производить больше одной трансформации или вообще задать матрицу преобразований.</p>
  <figure id="ZE1y" class="m_retina">
    <img src="https://img4.teletype.in/files/bd/46/bd4639b7-cbb6-4a21-8b41-3e7e1be5e634.png" width="230" />
  </figure>
  <h3 id="puUT">Параметры viewPort</h3>
  <p id="Ii9b">Последнее замечание сделаю относительно значений параметра <code>viewPort</code> тега <code>&lt;svg&gt;</code>.</p>
  <p id="BXgZ">Я долго не мог понять, как им пользоваться, пока не придумал такое объяснение.</p>
  <p id="IDV6">Окно просмотра характеризуется двумя парами значений. Первая — положение окна просмотра в мировых (или пользовательских) координатах. По сути это просто точка на пользовательском чертеже.</p>
  <p id="SDSf">Вторая пара задает количество точек на пользовательском чертеже, которые мы видим в окно просмотра, соответственно по горизонтали и вертикали, но при этом само окно имеет размер, задаваемый параметрами ширины и высоты тега <code>&lt;svg&gt;</code>. </p>
  <p id="yeCV">То есть, <code>viewPort</code> имеет фиксированный размер на экране или в браузере, а вот содержимое его подстраивается с учетом коэффициентов, получаемых соотношением размеров из окна просмотра и тега <code>&lt;svg&gt;</code>. Кому как, а мне так стало понятнее.</p>
  <p id="IHYN">UPD:</p>
  <p id="TCJf">В библиотеке подумали о том, что иногда можно опустить проверку параметров:</p>
  <pre id="4GO8">(with-svg-to-file
    (scene &#x27;svg-1.1-toplevel :height 230 :width 230 :view-box &quot;-20 -20 230 230&quot;)
    (#p&quot;~/devel/svg/coords.svg&quot; :if-exists :supersede)

  (style scene &quot;svg#toplevel {display:flex; transform: scaleY(-1);}&quot;)

  (style scene &quot;svg#toplevel g &gt; text {transform: scaleY(-1);}&quot;)

  (make-group scene (:id &quot;frame&quot;)
    (draw*
     (:rect :x -20 :y -20 :height 230 :width 230)
     :fill &quot;#EEEEEE&quot; :stroke &quot;none&quot;))

  (make-group scene (:id &quot;axes&quot;)
    (draw*
     (:line :x1 0 :y1 -10 :x2 0 :y2 200) :stroke &quot;green&quot;)
    (draw*
     (:line :x1 -10 :y1 0 :x2 200 :y2 0) :stroke &quot;green&quot;))

  (without-attribute-check 
    (let ((texts (make-group scene (:id &quot;texts&quot;))))
      (make-group texts (:transform &quot;translate(20, 20)&quot;)
	(text* () &quot;Привет&quot;))
      (make-group texts (:transform &quot;translate(30, 40)&quot;)
	(text*  () &quot;Мир&quot;))
      (make-group texts (:transform &quot;translate(30, 60) rotate(90)&quot;)
	(text* () &quot;SVG&quot;)))))</pre>
  <p id="c91C">см. (<code>without-attribute-check ... )</code></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@it_tale/why-create-new-programming-languages</guid><link>https://teletype.in/@it_tale/why-create-new-programming-languages?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale</link><comments>https://teletype.in/@it_tale/why-create-new-programming-languages?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=it_tale#comments</comments><dc:creator>it_tale</dc:creator><title>Зачем делать новый язык программирования?</title><pubDate>Wed, 28 Feb 2024 15:05:30 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/9e/9b/9e9b985f-f56b-4f6d-a715-4105f1000e1c.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/16/58/16584b6a-9bd8-4ffe-8c4a-e20e503a2c32.png"></img>Копия статьи с Хабра от 31.01.2024]]></description><content:encoded><![CDATA[
  <blockquote id="JtgZ">Копия <a href="https://habr.com/ru/articles/790422/" target="_blank">статьи</a> с Хабра от 31.01.2024</blockquote>
  <figure id="U7Sz" class="m_column" data-caption-align="center">
    <img src="https://img2.teletype.in/files/16/58/16584b6a-9bd8-4ffe-8c4a-e20e503a2c32.png" />
    <figcaption>Георгий Победоносец победил дракона</figcaption>
  </figure>
  <p id="sk2X">Когда в публичном пространстве появляется информация о новом языке программирования, поднимается волна неприятия. Негатива столько, что хоть святых выноси!</p>
  <p id="0SSd">Причин у этого явления много и, скорее всего, сделать с ним ничего нельзя, такова уж человеческая природа.</p>
  <p id="KVpR">Однако можно подойти к вопросу рационально, и все-таки попробовать поискать ответ на вопрос, а зачем, собственно, создавать новый язык программирования?</p>
  <p id="ReRf">Попробуем разобрать мотивы, подвигающие людей на такую работу.</p>
  <h3 id="S1Ta">Личный творческий порыв</h3>
  <p id="7eFE">Зачем люди пишут статьи (включая эту), картины, идут в горы, спускаются на дно океана, вышивают крестиком, вяжут рыболовные сети и режут из дерева?</p>
  <p id="rDX3">Зачем вообще люди занимаются творчеством?</p>
  <p id="7bxb">Этим вопросом занимаются разные науки, для многих людей творчество — это экзистенциальный опыт, кто-то «не может не творить». Сам по себе ответ на вопрос «зачем люди творят» выходит далеко за рамки статьи о создании языков программирования.</p>
  <p id="84uf">Для нас важно отметить тот факт, что создание языка программирования и транслятора для него, процесс, безусловно, творческий, а потому захватывающий и очень интересный сам по себе.</p>
  <p id="o5An">Поэтому многие тратят свое время, силы, знания, чтобы создать новый способ общения между человеком и компьютером (или людей между собой, ведь язык программирования еще и средство передачи смыслов между людьми).</p>
  <p id="fRKZ">Сам факт того, что компьютеру можно что-то «объяснить», написав код и запустив его, завораживает и потрясает воображение. А уж возможность управлять этим процессом в самом глубинном значении этого слова вызывает внутренний восторг и благоговение.</p>
  <p id="Chda">Процесс трансформации написанного текста в действие, выполняемое бездушной машиной, имеет магический, почти сакральный смысл.</p>
  <p id="3LNh">Программирование само по себе для постороннего наблюдателя загадочно, а потому часто притягательно, создание же средства для изготовления программ еще более загадочно. И интересно.</p>
  <h3 id="qYrA">Академический интерес</h3>
  <p id="9MNP">Очень близко к творчеству стоит научная деятельность. Нередко языки программирования создаются для проверки или реализации той или иной концепции.</p>
  <p id="6Sdn">Так, язык <a href="http://www.muppetlabs.com/~breadbox/bf/" target="_blank">Brainfuck</a> вырос из попытки создать Тьюринг-полный язык программирования, для которого можно создать минимально возможный компилятор. Первая версия компилятора для Amiga OS 2.0 занимала 240 байт, позднее размер удалось сократить и он стал занимать менее 200 байт.</p>
  <p id="cphZ">Языки <a href="https://wiki.portal.chalmers.se/agda/pmwiki.php" target="_blank">Agda</a>, <a href="https://coq.inria.fr/" target="_blank">Coq</a>, <a href="https://www.idris-lang.org/" target="_blank">Idris</a> разработаны для проведения исследований в области спецификаций и доказательств.</p>
  <p id="IGJJ">Многие исследовательские проекты, изначально написанные, скажем, на Haskell или OCaml, нередко перерастают в самостоятельные языки.</p>
  <p id="7UAg">В хабе <a href="https://habr.com/ru/hubs/crazydev/articles/" target="_blank">Ненормальное программирование</a> немало статей как раз про языки такого рода.</p>
  <h3 id="ACge">Поддержка предметной области</h3>
  <p id="le1m">Перейдем к более приземленным материям.</p>
  <p id="waAZ">Часто бывает так, что предметная область, в которой приходится решать те или иные задачи, сравнительно неплохо формализована и имеет устоявшийся понятийный аппарат. Например, финансовая система или графическая разработка в CAD системах.</p>
  <p id="TEux">Можно решать задачи в предметных областях при помощи существующего инструментария, в первую очередь, существующих языков программирования и библиотек. Но бывает уместно создать язык, в который можно вложить логику предметной области. Тогда профильные специалисты смогут использовать собственные знания и навыки для решения своих задач без привлечения разработчиков.</p>
  <p id="DRms">В России таким примером служит язык 1С, разработанный для автоматизации задач бухгалтерского учета. Другие примеры подобного рода — AutoLISP для CAD, Asymptote для подготовки математических иллюстраций, G-Code для управления станками с ЧПУ и т.д.</p>
  <p id="5AWX">Такие языки принято называть DSL (domain specific language) или по-русски — <a href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BC%D0%B5%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA" target="_blank">предметно-ориентированный язык</a>.</p>
  <p id="qJ51">Границы этого термина довольно размыты, да и не хочется сейчас акцентироваться на определениях. Важным критерием таких языков, как мне кажется, стоит считать приоритет предметной области над языком, т.е. язык является вторичным по отношению к используемой системе понятий.</p>
  <h3 id="LZDj">Предоставление интерфейса к набору библиотек</h3>
  <p id="mOGE">При разработке большой программной библиотеки может возникнуть ситуация, когда сама по себе библиотека становится «предметной областью». Тогда можно создать язык программирования, построенный поверх этой библиотеки. Пример такого подхода — язык <a href="https://doc.qt.io/qt-6/qmlapplications.html" target="_blank">QML</a>из библиотеки QT. И, хотя сам язык разрабатывался как средство разработки интерфейсов пользователя, построенный поверх QT, фактически из него можно вызывать почти всё (если не строго всё) содержимое библиотеки, в свою очередь написанной на C++.</p>
  <p id="edjn">Есть и другие примеры такого подхода. Так, к таким языкам можно отнести JavaScript, хотя он заметно шире, чем представлено в настоящем параграфе. Похожими свойствами обладает язык <a href="https://www.codeproject.com/Articles/33662/TIScript-Language-A-Gentle-Extension-of-JavaScript" target="_blank">TISript</a> из проекта <a href="https://sciter.com/" target="_blank">Sciter</a> (позже, впрочем, замененный на JavaScript).</p>
  <p id="tR9c">Благодаря легкости встраивания и легкости синтаксиса, свойство «быть надстройкой над библиотекой» появляется при встраивании языка Lua или <a href="https://ecl.common-lisp.dev/index.html" target="_blank">ECL</a> (Embeddable Common Lisp) внутрь более крупного проекта.</p>
  <h3 id="pU0X">Причины коммерческого характера</h3>
  <p id="QBOi">В конце 90-х годов, когда язык Java начал набирать обороты и уже имел хорошую пользовательскую базу, судебные тяжбы по поводу корректного использования виртуальной машины, самого языка и другого инструментария были не редкостью.</p>
  <p id="ypU0">Microsoft пыталась договориться с Sun Microsystem (разработчиком Java) о разных аспектах использования языка, в том числе в рекламных материалах, но в какие-то моменты стороны шли в суд, поскольку не удавалось прийти к соглашению.</p>
  <p id="eLgC">В том числе, для того, чтобы не зависеть от других компаний в своем бизнесе, компания Microsoft начала разработку языка C#. Больше того, оба этих языка в начале своего пути были схожими концептуально, но позже значительно разошлись.</p>
  <h3 id="vQSI">Безопасность</h3>
  <p id="ZKxG">Если посмотреть на индексы <a href="https://www.tiobe.com/" target="_blank">TIOBE</a> и <a href="https://pypl.github.io/PYPL.html" target="_blank">PYPL</a>, то окажется, что в обоих индексах языки из первой десятки прямо или косвенно (через спонсорство) контролируются американцами и европейцами. В текущих реалиях неплохо бы задуматься, каким инструментарием приходится пользоваться в нашей стране.</p>
  <p id="EjpB">Отношения к лицензионным соглашениям в российском сегменте интернета часто вызывает улыбку, но с точки зрения бизнеса — вопрос серьезный.</p>
  <p id="b1iV">Компиляторы и библиотеки языков в подавляющем большинстве поставляются с открытыми исходными текстами. Однако, открытость исходников не должна вводить в заблуждение, закладки и уязвимости спокойно <a href="https://www.kaspersky.ru/blog/open-source-top-10-risks/35092/" target="_blank">проникают</a> в программы.</p>
  <p id="ZMHM">Специалисты по безопасности тут могут много рассказать, но одно можно точно сказать, что если инструмент разрабатывается внутри страны и контролируется, это существенно улучшает вопросы, связанные с безопасностью.</p>
  <p id="5eMk">Это же можно отнести и на уровень отдельной компании. Безопасность проще контролировать, если вы управляете всей технологической цепочкой, включая, в данном случае, язык программирования и компилятор.</p>
  <h3 id="3gDC">Производительность</h3>
  <p id="MKxV">Ранее мы уже сказали про создание языка для поддержки некоторой предметной области. Однако, иногда предметная область столь широка, что имеет смысл создать язык общего назначения, который, тем не менее, был бы специально предназначен для эффективных вычислений именно в этой области.</p>
  <p id="RAw5">К таким областям, на мой взгляд, стоит отнести математические вычисления (в просторечии «числодробилки»). В этой среде есть несколько значимых языков, но особо хочу выделить язык <a href="https://julialang.org/" target="_blank">Julia</a>.</p>
  <p id="GyRL">Этот язык целенаправленно создавался как язык высокопроизводительных математических вычислений, на котором можно писать большие и сложные программы.</p>
  <h3 id="1KHL">Укрупнение или сужение семантики</h3>
  <p id="xCXe">Этот пункт относится не к языкам как таковым. Скорее речь должна идти о семантике языка, но, поскольку в процессе работы генерируется код, решил этот пункт выделить.</p>
  <p id="eByF">Код на языке программирования может не сразу преобразовываться в байткод целевой машины или в бинарный код, а в некоторое промежуточное представление, которое, тем не менее, представляет собой текст на другом языке программирования. Технически речь в данном случае идет не о компиляции, а о так называемой транспиляции.</p>
  <p id="Pspy">Общий смысл сгенерированного кода при таком подходе сохраняется, но за счет использования другой формы представления компилятор или другой инструмент может производить разнообразные оптимизации и трансформации.</p>
  <p id="4c1w">Так, например, код с языка высокого уровня может переводиться в ассемблер или, что бывает значительно чаще, в форму LLVM IR.</p>
  <p id="CqGq">Бывают и примеры обратного преобразования, когда код из более низкоуровневого представления преобразуется в более высокоуровневое.</p>
  <h3 id="bQpY">Имиджевые причины</h3>
  <p id="b2fc">Разработка языка — это долго и дорого. Если вместе с языком разрабатывать ещё и компилятор, это ещё дольше и ещё дороже. (Если предыдущая фраза показалась вам странной, то да, разработка языка и разработка компилятора к нему — разные процессы). Позволить себе такое могут либо совсем упертые профессионалы, либо организации, способные оценить потенциальные выгоды от такой разработки и вложить несколько человеколет в разработку.</p>
  <h3 id="3qzI">Зачем я все это пишу?</h3>
  <p id="7jqT">Я сам уже почти 10 лет профессионально занимаюсь созданием языков программирования и компиляторов, меня лично трудно смутить негативом по отношению к плодам своего труда.</p>
  <p id="8yIm">Мне хочется, чтобы читатель, при виде очередного языка, «непонятно зачем созданного, то же самое можно сделать на языке <em>Х</em>» вспомнил, что у такой работы и такой публикации есть вполне рациональные мотивы. Ведь есть множество причин, способных побуждать к изготовлению языка.</p>
  <p id="BgBN">В нашей стране очень много сильных компиляторщиков. Если посмотреть на репозитории языков и компиляторов, то активные контрибьюторы из России есть во всех более-менее крупных проектах, в некоторых случаях даже на ведущих ролях.</p>
  <p id="uizj">Однако, и это вторая проблема, в российской индустрии в настоящее время не видно тенденции к сохранению и развитию навыков в указанной области. Мы пользуемся инструментами, созданными в других странах, что в текущем политическом моменте несколько самонадеянно. Имеющиеся же проекты или не воспринимаются серьезно, или игнорируются. Большая часть известных мне проектов либо ориентирована на западный рынок, либо имеет какой-то полумаргинальный статус.</p>
  <p id="kfvT">Да, международное сотрудничество идет, пусть и в виде приема патчей в репозитории. Пока идет. Важно не упустить момент, когда станет поздно и окажется, что «станки для программистов» делать и некому, и незачем.</p>
  <p id="jKLf">Импортозамещение, каким бы казенным ни было это слово, важно делать и тут. Логичным развитием ситуации с языками и компиляторами в стране считаю дополнение нормативной базы о реестре отечественного ПО таким образом, чтобы компаниям было выгодно разрабатывать софт с помощью инструментария, сделанного в России.</p>
  <p id="5t0p">P.S. На КДПВ святой Георгий Победоносец, по преданию победивший дракона.</p>
  <p id="TQKv">P.P.S. Если вы знаете какую-то компанию или людей, делающих языки, компиляторы и другой подобный инструментарий в нашей стране, упомяните их в комментариях. Страна должна знать своих героев!</p>

]]></content:encoded></item></channel></rss>