Я тут немножко записываю то, как решаю задачки Advent of Code 2016 на Common Lisp. Навёрстываю упущенное, так сказать. Пока хватает стандартной библиотеки, но может быть свой парсер притащу в итоге — получился вполне удобным. Ещё надо будет поиграться с альтернативными наборами батареек вроде Radical Utilities, пусть даже большая часть подобных библиотек — оголтелая вкусовщина
Кстати, если вам нравится читать всякие истории из жизни программистов старой школы, можете глянуть на эту статью: "Lisping at JPL Revisited". Автор пишет о том, что он думает о прошлом себе, написавшем оригинальную статью "Lisping at JPL" в начале нулевых, и как эволюционировали его (автора) отношения с Common Lisp. И оригинальную статью почитайте тоже: она рассказывает про программирование марсианских роверов на Lisp.
А кстати эта статья приходится потому, что Rondam Ramblings (так автора зовут) программирует вот уже почти сорок лет на своём языке, который он построил на основе CL — очень "лисперская" история и тоже вся наполнена вкусовщиной. При этом автор считает, что именно такие личные истории и привели к тому, что экосистема у Common Lisp ныне сильно фрагментирована. Так что "критику лиспов от лица лиспера" вы в статье тоже найдёте.
P.S. В процессе записывания процесса решения у меня пока обнаруживаются всякие проблемы вроде пропадания кадров в записях стримов силами Telegram, с которым раньше не было проблем. Но в принципе оно смотрибельно, да и с третьего видео я перешёл на локальную запись с помощью OBS, так что пропуски кадров должны уйти в прошлое. И OBS хотя бы не вставляет заглушки свои в ролик, как это телеграм делает.
:)Кстати, если вам нравится читать всякие истории из жизни программистов старой школы, можете глянуть на эту статью: "Lisping at JPL Revisited". Автор пишет о том, что он думает о прошлом себе, написавшем оригинальную статью "Lisping at JPL" в начале нулевых, и как эволюционировали его (автора) отношения с Common Lisp. И оригинальную статью почитайте тоже: она рассказывает про программирование марсианских роверов на Lisp.
А кстати эта статья приходится потому, что Rondam Ramblings (так автора зовут) программирует вот уже почти сорок лет на своём языке, который он построил на основе CL — очень "лисперская" история и тоже вся наполнена вкусовщиной. При этом автор считает, что именно такие личные истории и привели к тому, что экосистема у Common Lisp ныне сильно фрагментирована. Так что "критику лиспов от лица лиспера" вы в статье тоже найдёте.
P.S. В процессе записывания процесса решения у меня пока обнаруживаются всякие проблемы вроде пропадания кадров в записях стримов силами Telegram, с которым раньше не было проблем. Но в принципе оно смотрибельно, да и с третьего видео я перешёл на локальную запись с помощью OBS, так что пропуски кадров должны уйти в прошлое. И OBS хотя бы не вставляет заглушки свои в ролик, как это телеграм делает.
👍9🤔2🔥1
Раз уж я тут с Common Lisp играюсь в последнее время и сюда об этом пишу, то прорекламирую один YouTubeканал: "IT Муравейник".
Автор недавно начал рассказывать про то, как вообще живётся в мире CL, как его готовить и с чем вприкуску есть. А сегодня Александр выложил ролик про библиотечку cl-reex в формате "сегодня я поковырял вот это вот" — у автора раньше уже был заход в "рассматривание по библиотеке в день" и очень даже длинный, в 220 дней (мне бы так)!
Так вот, у меня от
Потом я, правда, видал примеры "серьёзного" использования Rx, и они мне понравились не так сильно. Мне гораздо больше нравится FRP, с тех пор, как я с ним поигрался в Elm, даже доклады делал про это всё. А потом был не рад, когда FRP из Elm выплили. Но это, как говорится, уже совсем другая история.
Однако, не могу не отметить, что в контексте с CL реактивщина в стиле Rx смотрится неплохо! Потому что язык процедурный, мутировать состояние очень даже принято. Вот и сеть подписок строится путём оформления подписок для существующих наблюдателей. Зато макросы позволяют довольно приятно разгрузить синтаксис:
Надо будет попробовать написать какую-нибудь игрушку с логикой на cl-reex. Только сначала нужно найти библиотеку, которая с канвой работает не слишком многословно. Может быть в "IT Муравейнике" проскользнёт?
Автор недавно начал рассказывать про то, как вообще живётся в мире CL, как его готовить и с чем вприкуску есть. А сегодня Александр выложил ролик про библиотечку cl-reex в формате "сегодня я поковырял вот это вот" — у автора раньше уже был заход в "рассматривание по библиотеке в день" и очень даже длинный, в 220 дней (мне бы так)!
Так вот, у меня от
cl-reex возник тот самый "вьетнамский флешбэк": вспомнилось, как я проходил на Coursera курс "Functional Program Design in Scala", когда он только появился, в 2012 (!) — с отличием закончил, между прочим! Курс до сих пор существует и в одной из частей знакомит с реактивщиной в Rxстиле с наблюдателями и подписками. Мне тогда эта идея вполне понравилась, во многом потому, что в курсе подавалась интересно.Потом я, правда, видал примеры "серьёзного" использования Rx, и они мне понравились не так сильно. Мне гораздо больше нравится FRP, с тех пор, как я с ним поигрался в Elm, даже доклады делал про это всё. А потом был не рад, когда FRP из Elm выплили. Но это, как говорится, уже совсем другая история.
Однако, не могу не отметить, что в контексте с CL реактивщина в стиле Rx смотрится неплохо! Потому что язык процедурный, мутировать состояние очень даже принято. Вот и сеть подписок строится путём оформления подписок для существующих наблюдателей. Зато макросы позволяют довольно приятно разгрузить синтаксис:
(defparameter observerНикаких вложенных вызовов, даже лямбды спрятаны за клозами вроде
(rx:make-observer
(rx:on-next (x) (print x))
(rx:on-error (x) (format t "error: ~S~%" x))
(rx:on-completed () (print "completed")) ))
rx:on-next — DSL в лучшем виде, если вы вообще любите такое, конечно.Надо будет попробовать написать какую-нибудь игрушку с логикой на cl-reex. Только сначала нужно найти библиотеку, которая с канвой работает не слишком многословно. Может быть в "IT Муравейнике" проскользнёт?
:)👍11
У меня на той неделе намечается стрим. Будет не столько сложная вёрстка какая-то, сколько просто разработка под браузер в целом: приложение с состоянием, local storage, походами в публичный API за данными. Так что будет не то чтобы очень красиво, но зато разнообразно :Р
А надумал я про это порассказывать потому, что сейчас книжку пишу про ClojureScript. Не то чтобы большую книгу про язык в целом, общо и широко, а в стиле "семи языков за семь недель" — познавательно-развлекательно с показом в первую очередь интересных особенностей языка и присущих ему подходов к проектированию приложений.
Изначально планировалась книга про три языка: TS, ClJS и PureScript, но мои соавторы пока не готовы публиковать свои порции, а я уже написал достаточно, чтобы имело смысл выложить в виде GitBook. Может ещё и Patreon какой-нить прикручу — вдруг кому понравится. А большая книга про три языка выйдет, когда выйдет. Может быть я сам, когда часть про ClJS добью, попробую помочь коллегам с TS или PS.
А надумал я про это порассказывать потому, что сейчас книжку пишу про ClojureScript. Не то чтобы большую книгу про язык в целом, общо и широко, а в стиле "семи языков за семь недель" — познавательно-развлекательно с показом в первую очередь интересных особенностей языка и присущих ему подходов к проектированию приложений.
Изначально планировалась книга про три языка: TS, ClJS и PureScript, но мои соавторы пока не готовы публиковать свои порции, а я уже написал достаточно, чтобы имело смысл выложить в виде GitBook. Может ещё и Patreon какой-нить прикручу — вдруг кому понравится. А большая книга про три языка выйдет, когда выйдет. Может быть я сам, когда часть про ClJS добью, попробую помочь коллегам с TS или PS.
YouTube
Функциональный фронтенд. ClojureScript — Часть 1 из 5
Исходный код проекта: https://github.com/astynax/cljs-pokedex
Алексей Пирогов на getmentor: https://getmentor.dev/mentor/aleksei-pirogov-3568
00:00 - заставка
04:50 - начало - вводное слово от Марка
06:45 - вводная от Алексея про Clojure и ClojureScript…
Алексей Пирогов на getmentor: https://getmentor.dev/mentor/aleksei-pirogov-3568
00:00 - заставка
04:50 - начало - вводное слово от Марка
06:45 - вводная от Алексея про Clojure и ClojureScript…
🔥19👍5🤔1
Постримил вторую часть приключений с ClojureScript. Сделал забор данных о покемонах через GraphQL, уложил оные в DataScript, попробовал погонять запросы. Естественно, наступил на половину граблей, даже REPL подвесил разок, но в целом доволен. Теперь нужно придумать, как many-to-many связи между "моделями" разложить на тройки, но это я в фоне попилю к следующему вторнику, когда третий стрим будет.
Кстати, backend у PokeAPI на Python/Django написан. А GraphQL делается силами Hasura, а это, на минуточку, уже проект, реализованный на Haskell! (Если что, Hasura — это такая штука, превращающая вашу базу в *PostgreSQL* в GraphQL endpoint с админкой и правами). Вместе с моим проектом на ClJS получается настоящий зоопарк
Кстати, backend у PokeAPI на Python/Django написан. А GraphQL делается силами Hasura, а это, на минуточку, уже проект, реализованный на Haskell! (Если что, Hasura — это такая штука, превращающая вашу базу в *PostgreSQL* в GraphQL endpoint с админкой и правами). Вместе с моим проектом на ClJS получается настоящий зоопарк
:)🔥10
Третью часть вчера постримил. Как всегда, не без граблей :) На этот раз подвёл PokeAPI — у них прилег GraphQL backend, о чём мне радостно сообщил CloudFlare прямо перед стримом.
А ведь я хотел сдампить себе выдачу, чтобы локальную копию иметь и не нагружать сервис лишний раз! Но, как в анекдоте про бэкапы, пришлось перейти из лагеря тех, кто ещё не делает, в лагерь тех, кто уже делает :)
Я даже пытался по-быстрому сдампить то, что у меня было сохранено на другим компе в запущенном REPL. Но в случае ClJS не так-то просто взять и что-то осмысленное сделать со структурой в несколько мегабайт. Я пробовал воткнуть в DOM ноду с
В процессе мокания наткнулся на пресловутый nil punning: когда спуск вглубь структуры натыкается на nil, вы не получаете ошибку, а вместо этого получаете nil в качестве результата. Это удобно, когда ты того хочешь, и неудобно, когда не хочешь. Но уж таков путь (в Clojure, как минимум). Да, кложуристы сказали бы (кое-кто таки сказал
В любом случае, я сделал таки тестовые данные. Это позволило порешать проблему с дублированием строк в выборке, предполагающей JOIN "табличек" в Datanoscript, связанных как "один-ко-многим". Силами БД я это не стал решать, просто пожонглировал мапками, но на то у нас и Data-Oriented Programming, чтобы обходиться обобщёнными структурами данных и превращать неудобные внешние данные в удобные внутренние посредством манипуляций над этими самыми структурами!
А ведь я хотел сдампить себе выдачу, чтобы локальную копию иметь и не нагружать сервис лишний раз! Но, как в анекдоте про бэкапы, пришлось перейти из лагеря тех, кто ещё не делает, в лагерь тех, кто уже делает :)
Я даже пытался по-быстрому сдампить то, что у меня было сохранено на другим компе в запущенном REPL. Но в случае ClJS не так-то просто взять и что-то осмысленное сделать со структурой в несколько мегабайт. Я пробовал воткнуть в DOM ноду с
<pre></pre>, чтобы потом скопипастить содержимое в файл. Но вставка выдала копию значения в REPL в качестве эха и это был конец: REPL помер в попытке вывести эти самые мегабайты — и со стороны Emacs, и в консоли браузера. Иными словами, не получилось сдампить, так что пришлось мокать.В процессе мокания наткнулся на пресловутый nil punning: когда спуск вглубь структуры натыкается на nil, вы не получаете ошибку, а вместо этого получаете nil в качестве результата. Это удобно, когда ты того хочешь, и неудобно, когда не хочешь. Но уж таков путь (в Clojure, как минимум). Да, кложуристы сказали бы (кое-кто таки сказал
;)), мол, надо было сразу спеку cделать. Да, надо было. Может быть и сделаю в следующей серии!В любом случае, я сделал таки тестовые данные. Это позволило порешать проблему с дублированием строк в выборке, предполагающей JOIN "табличек" в Datanoscript, связанных как "один-ко-многим". Силами БД я это не стал решать, просто пожонглировал мапками, но на то у нас и Data-Oriented Programming, чтобы обходиться обобщёнными структурами данных и превращать неудобные внешние данные в удобные внутренние посредством манипуляций над этими самыми структурами!
🔥8👍1
Вот и четвёртая часть.
Сегодня пробовал заменить react-based вёрстку на enfocus — это когда режешь селекторами готовый HTML-пример, а потом в прорези данные подставляешь. В своё время enlive и enfocus были вполне себе, а нынче, увы, enfocus "отгнил" — использует куски из google closure, которых и нет давно.
Попробовал более свежую (но не сильно) инкарнацию, которая делегирует "рендеринг" в Reagent или Om. Но и эта либа не завелась, потому что reagent вперёд убежал и тоже кое-какие из API-функций потерял в итоге. Итог выглядит так: всё, что было в экосистеме ClJS и отличалось от React, не выдержало конкуренции. Увы и ах.
Но не только провалы сегодня были. Были и успехи. Взял и натянул clojure.spec на входной JSON. Пусть будет, потом пригодится, когда буду внешнее представление во внутреннее перегонять — всё, как Data-Oriented Programming нам завещал!
В серии планируется заключительная трансляция про backend — для контраста с фронтом и просто потому, что там как-то макросы повыразительнее смотрятся (compojure возьму по олдскулу. Или bidi, как пойдёт).
Сегодня пробовал заменить react-based вёрстку на enfocus — это когда режешь селекторами готовый HTML-пример, а потом в прорези данные подставляешь. В своё время enlive и enfocus были вполне себе, а нынче, увы, enfocus "отгнил" — использует куски из google closure, которых и нет давно.
Попробовал более свежую (но не сильно) инкарнацию, которая делегирует "рендеринг" в Reagent или Om. Но и эта либа не завелась, потому что reagent вперёд убежал и тоже кое-какие из API-функций потерял в итоге. Итог выглядит так: всё, что было в экосистеме ClJS и отличалось от React, не выдержало конкуренции. Увы и ах.
Но не только провалы сегодня были. Были и успехи. Взял и натянул clojure.spec на входной JSON. Пусть будет, потом пригодится, когда буду внешнее представление во внутреннее перегонять — всё, как Data-Oriented Programming нам завещал!
В серии планируется заключительная трансляция про backend — для контраста с фронтом и просто потому, что там как-то макросы повыразительнее смотрятся (compojure возьму по олдскулу. Или bidi, как пойдёт).
👍5
Кстати, стримлю в рамках нашего клуба далеко не только я. На днях, например, у нас был гость, рассказавший популярно про Nix.
Я лично с Nix знаком давно, но всё равно кое-что новое почерпнул: узнал про Nixery. Это такой способ получить OCIсовместимый контейнер, содержащий заданные пакеты из Nix. Если вы знакомы с Nix, то можете считать, что это "
Для чего такое может быть нужно? Чтобы разово что-то запустить в песочнице, не подготавливая предварительно Dockerfile. Скажем, нужно вам что-то конвертировать с помощью pandoc, но оный у вас не установлен и устанавливать его не хочется ради однократного использования.
Да, конкретно образа с pandoc есть на DockerHub. Но что если вам хочется применить к документу фильтр, написанный, к примеру, на Racket? Придётся либо в shell внутри контейнера что-то доустанавливать, либо написать таки Dockerfile.
И я не хочу сказать, что написание Dockerfile — это плохой путь! Вот только Nixery позволяет получить сразу контейнер с установленными пакетами
Но стоит понимать, что Nixery не призван заменить написание Dockerfile или описание контейнеров силами самого Nix. Например, я пока не понял, можно ли зафиксировать версию nixpkgs, скажем, в теге контейнера. С другой стороны само наличие хранилища разных версий всех пакетов Nix звучит как дорогая затея.
Так что я буду смотреть на Nixery просто как на логичное дополнение для
Я лично с Nix знаком давно, но всё равно кое-что новое почерпнул: узнал про Nixery. Это такой способ получить OCIсовместимый контейнер, содержащий заданные пакеты из Nix. Если вы знакомы с Nix, то можете считать, что это "
nix-shell -p …", только в контейнере!Для чего такое может быть нужно? Чтобы разово что-то запустить в песочнице, не подготавливая предварительно Dockerfile. Скажем, нужно вам что-то конвертировать с помощью pandoc, но оный у вас не установлен и устанавливать его не хочется ради однократного использования.
Да, конкретно образа с pandoc есть на DockerHub. Но что если вам хочется применить к документу фильтр, написанный, к примеру, на Racket? Придётся либо в shell внутри контейнера что-то доустанавливать, либо написать таки Dockerfile.
И я не хочу сказать, что написание Dockerfile — это плохой путь! Вот только Nixery позволяет получить сразу контейнер с установленными пакетами
pandoc + racket без какого-либо конфигурирования: вам достаточно указать имя контейнера вида "nixery.dev/shell/pandoc/racket"! Слои таких контейнеров построены силами Nix, так что если вы будете запускать пересекающиеся множества пакетов, общие слои будут использованы повторно — это тоже очень приятно!Но стоит понимать, что Nixery не призван заменить написание Dockerfile или описание контейнеров силами самого Nix. Например, я пока не понял, можно ли зафиксировать версию nixpkgs, скажем, в теге контейнера. С другой стороны само наличие хранилища разных версий всех пакетов Nix звучит как дорогая затея.
Так что я буду смотреть на Nixery просто как на логичное дополнение для
nix-shell "вне проекта", такое же "нестабильное", но полезное для разовых экспериментов.👍5
Постримил вчера завершающий эпизод, как и планировалось, про backend (UPD: в значении "server side") для контраста. Взял привычные ring+compojure, проект завёл через leiningen. Да, я всё ещё готовлю Clojure именно так
Даже рассуждать о сервере, как о "функции", очень удобно: это как бы вынесенный из браузера вовне обработчик события нажатия на кнопку! Жаль, что на клиентской стороне не получится так просто спрятать вызов сервера за внешне синхронным вызовом callback.
Впрочем, макросами можно попробовать разбить такой "обработчик нажатия на кнопку" на собственно посылку запроса и continuation, обрабатывающий ответ на оный. И такие попытки уже есть! Например, проект electric — обязательно посмотрите, как выглядит тамошний DSL, позволяющий совместить в едином с виду фрагменте кода вызовы функций на сервере и клиенте с передачей результатов между ними.
А я пока серию стримов закончил. Но только лишь до следующего раза
:P
И нормально получилось, надо сказать! Всё используется так, как я запомнил десять лет назад, и это приятное ощущение постоянства. Да, видно, что где-то что-то причесали, документации стало больше, а велосипедов меньше. Но сам подход "backend — это функция request → response" всё ещё отлично работает. Так делают и в Python в виде WSGI, и в Haskell в виде warp/WAI. Даже middleware одинаково сделаны — как функции, принимающие старую функцию-обработчик и возвращающие новую.Даже рассуждать о сервере, как о "функции", очень удобно: это как бы вынесенный из браузера вовне обработчик события нажатия на кнопку! Жаль, что на клиентской стороне не получится так просто спрятать вызов сервера за внешне синхронным вызовом callback.
Впрочем, макросами можно попробовать разбить такой "обработчик нажатия на кнопку" на собственно посылку запроса и continuation, обрабатывающий ответ на оный. И такие попытки уже есть! Например, проект electric — обязательно посмотрите, как выглядит тамошний DSL, позволяющий совместить в едином с виду фрагменте кода вызовы функций на сервере и клиенте с передачей результатов между ними.
А я пока серию стримов закончил. Но только лишь до следующего раза
:)YouTube
Функциональный фронтенд. ClojureScript — Часть 5 из 5
Исходный код: https://github.com/astynax/cljs-pokedex проекта.Алексей Пирогов, наш бессменный докладчик и организатор встреч, продолжает серию воркшопов про ...
🔥5
Нагулял на днях идею: сделать web-app, который бы генерировал бесконечное подземелье. Причём нет цели получить проходимы лабиринт, достаточно того, чтобы оно интересно выглядело. Я вижу конечный результат в виде плавно прокручивающейся вниз карты, достраиваемой по мере достижения текущего конца. В процессе периодически менялись бы декорации, чтобы не так быстро наскучивало. Эдакий Screen Saver.
А придумал я эту штуку как способ заставить себя рисовать маленькие картинки чем чаще, тем лучше. Вот и будет стимул рисовать тайлы в стиле разных биомов, придумывать по нескольку альтернатив для одного и того же кусочка "шахта сверху-вниз с ответвлением вправо". Это всё можно завернуть в Web-интерфейс, который позволял бы загружать тайлы и размечать, указывая
- наличие или отсутствие выхода на каждой с четырёх сторон, чтобы мочь соединять
- тему/биом тайла, чтобы использовать единую тему для "геологического слоя"
- частоту появления, чтобы показывать секретные тайлы пореже
Да, с одной стороны генераторов карт подземелий предостаточно, с другой нынче можно нейронку попросить нагенерить хотя бы заготовку. Ещё бывают мероприятия, где люди коллективно рисуют большую картину по кусочкам. Но я не видел ни одного варианта, где генерация была бы случайной, и при этом можно было бы загружать свои кусочки да ещё и от лица разных пользователей (ага, социальные функции!).
При этом проект не выглядит сколько-нибудь сложным с технической стороны, поэтому я сам его, скорее всего, не стану делать. А вот если кто-то решит украсть идею, то я бы попользовался результатом :)
Или можем коллективно поделать, если кто-то поучиться хочет на вполне чётко очерченном проекте. Можно сделать на Haskell/Yesod, Python/Django, Clojure/ClJS/whatever. Тут я готов с менторской стороны выступать, у самого хватит запалу только на небольшую часть кода.
А придумал я эту штуку как способ заставить себя рисовать маленькие картинки чем чаще, тем лучше. Вот и будет стимул рисовать тайлы в стиле разных биомов, придумывать по нескольку альтернатив для одного и того же кусочка "шахта сверху-вниз с ответвлением вправо". Это всё можно завернуть в Web-интерфейс, который позволял бы загружать тайлы и размечать, указывая
- наличие или отсутствие выхода на каждой с четырёх сторон, чтобы мочь соединять
- тему/биом тайла, чтобы использовать единую тему для "геологического слоя"
- частоту появления, чтобы показывать секретные тайлы пореже
Да, с одной стороны генераторов карт подземелий предостаточно, с другой нынче можно нейронку попросить нагенерить хотя бы заготовку. Ещё бывают мероприятия, где люди коллективно рисуют большую картину по кусочкам. Но я не видел ни одного варианта, где генерация была бы случайной, и при этом можно было бы загружать свои кусочки да ещё и от лица разных пользователей (ага, социальные функции!).
При этом проект не выглядит сколько-нибудь сложным с технической стороны, поэтому я сам его, скорее всего, не стану делать. А вот если кто-то решит украсть идею, то я бы попользовался результатом :)
Или можем коллективно поделать, если кто-то поучиться хочет на вполне чётко очерченном проекте. Можно сделать на Haskell/Yesod, Python/Django, Clojure/ClJS/whatever. Тут я готов с менторской стороны выступать, у самого хватит запалу только на небольшую часть кода.
👍9🔥1
Я, как в далёком прошлом пользователь Windows со стажем, конечно же слушал музыку с помощью Winamp. В основном сидел на второй версии, потом пересел на AIMP, затем на Foobar2000. Даже свой плеер писал с системой плагинов и рекурсивными плейлистами — как-нибудь напишу про это.
Плееров было много, но для меня Winamp так о остался первой программой, которая показала, насколько необычно может выглядеть ПО на Windows. И пусть тот же Sonique) появился на моём горизонте не сильно позже, а выглядел гораздо более футуристично, да и Windows Media Player тоже в какой-то момент научился "шкуры" менять, но к тому моменту я уже знал, что так можно. И знал, как это делается — даже отверстия в окнах научился делать средствами WinAPI и regions.
В народе, конечно же, что Winamp был любим ещё и за то, что мог ещё и менять внешний вид. Это для многих была, опять же, первая программа, внешний вид которой можно было выбирать по вкусу — чтобы плеер выглядел, как постер к "Зачарованным", скажем. И разнообразие шкурок было столь велико потому, что формат оных был дружественным любому начинающему творцу, умеющему применять WinZIP и MS Paint — шкурки были ZIP-архивами с BMP-файлами внутри!
Некоторую сложность для художников по коже могли представлять текстовые конфигурационные файлы, содержащие помимо прочих метаданных описание того, какими цветами должен был мигать анализатор спектра. Цвета задавались в 16-ричном представлении RGB-цветов, а это уже не очень дружественно для обычного пользователя. Так что цвета для "эквалайзера" (ух, как же меня раздражает, когда так про спектроскоп говорят) обычно копировались из другой шкурки.
Меня, кстати, как-то товарищ попросил облегчить эту самую возню с цветами и я написал на Delphi программу для генерации палитр — в ней даже можно было в рамках набора цветов выбрать пару точек, указать их цвета, а точки между ними заполнить оттенками, чтобы получился градиент. Я даже научился делать градиенты сам — интернета у меня не было тогда, так что экспериментировал
Ещё одна история из того времени вспоминается. Приличная доля дисков с "Дискографиями группы XYZ в MP3" в автозапуске содержала всё тот же Winamp с заготовленным плейлистом или какую-то программу-обоболочку, которая выводила обложки альбомов и тексты песен умела отображать, но играла музыку силами того же Winamp. Вот только этот Winamp при первом запуске молча переписывал на себя файловые ассоциации — да, вот этот вот Winamp на вашем приводе D: становился проигрывателем по умолчанию для всех медиа-файлов! И если диска из этой серии "дискографий" в приводе не было, то и музыку вы послушать не могли. Причём отучить "портативную" версию Winamp брать на себя слишком много было несложно, но авторы этих сборников просто не стали заморачиваться
Я в какой-то момент устал от того, что все эти дискографии настолько халтурно сделаны. И написал свою оболочку для дискографии "Алисы" — чёрное окно, красные буквы, всё как положено. Тексты песен показывала, музыку играла сама — силами WMPlayer component. Ещё и записал всю эту красоту на болванку из чёрного ИК-прозрачного пластика!
Что ни говори, Winamp — целое явление и пласт культуры. Авторы, правда, в какой-то момент свернули не туда. В том числе и усложнив модификацию внешнего вида, поскольку в интерфейсе появились всякие выдвигающиеся панели и само окно стало "резиновым". Так что культура выделки шкур потихоньку исчезла. Остались только очаги вроде XMMS на unix-системах.
Плееров было много, но для меня Winamp так о остался первой программой, которая показала, насколько необычно может выглядеть ПО на Windows. И пусть тот же Sonique) появился на моём горизонте не сильно позже, а выглядел гораздо более футуристично, да и Windows Media Player тоже в какой-то момент научился "шкуры" менять, но к тому моменту я уже знал, что так можно. И знал, как это делается — даже отверстия в окнах научился делать средствами WinAPI и regions.
В народе, конечно же, что Winamp был любим ещё и за то, что мог ещё и менять внешний вид. Это для многих была, опять же, первая программа, внешний вид которой можно было выбирать по вкусу — чтобы плеер выглядел, как постер к "Зачарованным", скажем. И разнообразие шкурок было столь велико потому, что формат оных был дружественным любому начинающему творцу, умеющему применять WinZIP и MS Paint — шкурки были ZIP-архивами с BMP-файлами внутри!
Некоторую сложность для художников по коже могли представлять текстовые конфигурационные файлы, содержащие помимо прочих метаданных описание того, какими цветами должен был мигать анализатор спектра. Цвета задавались в 16-ричном представлении RGB-цветов, а это уже не очень дружественно для обычного пользователя. Так что цвета для "эквалайзера" (ух, как же меня раздражает, когда так про спектроскоп говорят) обычно копировались из другой шкурки.
Меня, кстати, как-то товарищ попросил облегчить эту самую возню с цветами и я написал на Delphi программу для генерации палитр — в ней даже можно было в рамках набора цветов выбрать пару точек, указать их цвета, а точки между ними заполнить оттенками, чтобы получился градиент. Я даже научился делать градиенты сам — интернета у меня не было тогда, так что экспериментировал
:) Да, градиенты в RGB — это сомнительная затея, сказал бы я нынешний себе тогдашнему, но заказчик мой остался доволен!Ещё одна история из того времени вспоминается. Приличная доля дисков с "Дискографиями группы XYZ в MP3" в автозапуске содержала всё тот же Winamp с заготовленным плейлистом или какую-то программу-обоболочку, которая выводила обложки альбомов и тексты песен умела отображать, но играла музыку силами того же Winamp. Вот только этот Winamp при первом запуске молча переписывал на себя файловые ассоциации — да, вот этот вот Winamp на вашем приводе D: становился проигрывателем по умолчанию для всех медиа-файлов! И если диска из этой серии "дискографий" в приводе не было, то и музыку вы послушать не могли. Причём отучить "портативную" версию Winamp брать на себя слишком много было несложно, но авторы этих сборников просто не стали заморачиваться
:) На таких дисках ещё и шкурка у WA была нестандартная, но всегда одна и та же "зелёненькая" — среди моих знакомых были даже ценители именно её.Я в какой-то момент устал от того, что все эти дискографии настолько халтурно сделаны. И написал свою оболочку для дискографии "Алисы" — чёрное окно, красные буквы, всё как положено. Тексты песен показывала, музыку играла сама — силами WMPlayer component. Ещё и записал всю эту красоту на болванку из чёрного ИК-прозрачного пластика!
Что ни говори, Winamp — целое явление и пласт культуры. Авторы, правда, в какой-то момент свернули не туда. В том числе и усложнив модификацию внешнего вида, поскольку в интерфейсе появились всякие выдвигающиеся панели и само окно стало "резиновым". Так что культура выделки шкур потихоньку исчезла. Остались только очаги вроде XMMS на unix-системах.
🔥4👍2💩1
(Разделил публикацию на две, а то опять в одну Телеграм не захотел умещать. Читайте выше начало)
А ещё Winamp 2 жив в виде Webamp — открытой реализации большей части функций оригинала с помощью Web-технологий. Появился Webamp году в 2014, так что проект это достаточно взрослый. Даже визуализации музыки показывать умеет силами WebGL — да-да, тот самый MilkDrop, только прямо в браузере! И, конечно же, шкурки поддерживаются оригинальные, у проекта даже есть целый музей: Winamp Skin Museum — вот тут-то вы точно сможете найти ту самую вашу любимую шкурку с Сакурой, собирательницей карт или с Бредом Питтом в золоте. И мало того, что любой экспонат можно рассмотреть, так все они ещё и действующие, благодаря всё тому же Webamp!
А ещё Winamp 2 жив в виде Webamp — открытой реализации большей части функций оригинала с помощью Web-технологий. Появился Webamp году в 2014, так что проект это достаточно взрослый. Даже визуализации музыки показывать умеет силами WebGL — да-да, тот самый MilkDrop, только прямо в браузере! И, конечно же, шкурки поддерживаются оригинальные, у проекта даже есть целый музей: Winamp Skin Museum — вот тут-то вы точно сможете найти ту самую вашу любимую шкурку с Сакурой, собирательницей карт или с Бредом Питтом в золоте. И мало того, что любой экспонат можно рассмотреть, так все они ещё и действующие, благодаря всё тому же Webamp!
🔥15👍1💩1
Недавно вышел выпуск подкаста "Подлодка" про creative coding. Выпуск хорош и для тех, кто давно знаком с темой, и как точка входа тоже сработает.
Мне самому эта тема достаточно близка: я картинки кодом рисую года с 1995, тогда на QBASIC, потом на всём подряд. И тут про generative art писал — уже про Racket и его библиотеку с рисующими комбинаторами. Мне в целом нравится такое вот комбинирование примитивов, потому что очень хорошо сочетается с ФП и рекурсией в частности. А рекурсия — это уже первый шаг к фракталам, не требующий при этом какой-то особой математики (комплексные числа точно вспоминать не приходится, это вам не визуализация множества Мандельброта)
В упомянутом в начале подкасте описывается рисование с помощью Kotlin. В том числе некоторое количество времени уделено фреймворку OPENRNDR. Если кому-то это о чём-то скажет, то это быстрый и мощный аналог Processing (про последнего тоже в покасте можно услышать). Я, памятуя о том, что в Processing чаще всего всё рисуется по координатам как в старом добром BASIC, не надеялся особо на то, что в OPENRNDR найдётся похожая на любимые мною комбинаторы машинерия.
Так и вышло. Всё рисуется от лица Drawer, который умеет "нарисовать кружок по смещению с использованием текущих заливки и обводки". НО, при этом на сам Drawer можно накладывать трансформации вроде сдвига и поворота. И трансформации повлияют на то, где фактически будет отображены элементы, которые мы попросим Drawer для нас нарисовать! И если мы вдруг захотим получить рисунок с помощью рекурсии, укладывая составные части коллажа, скажем, по спирали, то нам достаточно будет рисовать "голову" и применять трансформацию на "остаток спирали".
Вот только если в рекурсивном процессе подразумевается какое-то ветвление, то неплохо бы иметь возможность запомнить состояние Drawer перед запуском отрисовки очередной "ветви", а потом это состояние восстанавливать. И для этого есть готовое средство: стеки трансформаций, стилей, проекций (да, такие тоже есть). Вы делаете
И, раз уж я об этом пишу, логично было бы предположить, что я уже что-то порисовал. Да, порисовал! Взял одну свою старую работу, похожую на достаточно удачный пример для проверки возможностей, и реализовал на OPENRANDR. Результат приложу в виде картинки отдельным постом, но в реальности картинка у меня даже анимированная получилась — мигает "точками" в кубиках. Значимая часть выглядит так — это вся программа, включая описание приложения, за скобками остался Gradle-проект, который я по шаблону сделал, так что там ничего интересного.
Отдельно отмечу то, что в коде означает
В будущем я планирую поглубже поковырять эту штуку. Попробую реализовать любимые мной комбинаторы в каком-то приближении. Может быть постримлю процесс. А вы сходите на сайт фреймворка — там есть примеры, гораздо более впечатляющие, чем мои картинки
Мне самому эта тема достаточно близка: я картинки кодом рисую года с 1995, тогда на QBASIC, потом на всём подряд. И тут про generative art писал — уже про Racket и его библиотеку с рисующими комбинаторами. Мне в целом нравится такое вот комбинирование примитивов, потому что очень хорошо сочетается с ФП и рекурсией в частности. А рекурсия — это уже первый шаг к фракталам, не требующий при этом какой-то особой математики (комплексные числа точно вспоминать не приходится, это вам не визуализация множества Мандельброта)
В упомянутом в начале подкасте описывается рисование с помощью Kotlin. В том числе некоторое количество времени уделено фреймворку OPENRNDR. Если кому-то это о чём-то скажет, то это быстрый и мощный аналог Processing (про последнего тоже в покасте можно услышать). Я, памятуя о том, что в Processing чаще всего всё рисуется по координатам как в старом добром BASIC, не надеялся особо на то, что в OPENRNDR найдётся похожая на любимые мною комбинаторы машинерия.
Так и вышло. Всё рисуется от лица Drawer, который умеет "нарисовать кружок по смещению с использованием текущих заливки и обводки". НО, при этом на сам Drawer можно накладывать трансформации вроде сдвига и поворота. И трансформации повлияют на то, где фактически будет отображены элементы, которые мы попросим Drawer для нас нарисовать! И если мы вдруг захотим получить рисунок с помощью рекурсии, укладывая составные части коллажа, скажем, по спирали, то нам достаточно будет рисовать "голову" и применять трансформацию на "остаток спирали".
Вот только если в рекурсивном процессе подразумевается какое-то ветвление, то неплохо бы иметь возможность запомнить состояние Drawer перед запуском отрисовки очередной "ветви", а потом это состояние восстанавливать. И для этого есть готовое средство: стеки трансформаций, стилей, проекций (да, такие тоже есть). Вы делаете
pushTransformation(), рисуете ветвь, потом выполняете popTransformation() и Drawer готов к рисованию новой ветви — и вам не нужно высчитывать, на сколько в итоге сдвинулся базис координат и на сколько повернулись оси.И, раз уж я об этом пишу, логично было бы предположить, что я уже что-то порисовал. Да, порисовал! Взял одну свою старую работу, похожую на достаточно удачный пример для проверки возможностей, и реализовал на OPENRANDR. Результат приложу в виде картинки отдельным постом, но в реальности картинка у меня даже анимированная получилась — мигает "точками" в кубиках. Значимая часть выглядит так — это вся программа, включая описание приложения, за скобками остался Gradle-проект, который я по шаблону сделал, так что там ничего интересного.
Отдельно отмечу то, что в коде означает
oliveProgram: это не намёк на оливковый цвет, а указание на то, что программа должна быть "live". Такие программы в OPENRANDR отслеживают изменения в соответствующем файле с кодом и без перезапуска применяют эти изменения — и это в компилируемом языке! Да, есть у этой горячей загрузки ограничения: применяются изменения только из той части кода, которая является "телом" oliveProgram, внешние по отношению к блоку функции, например, не подменяются. Но даже такие ограничения позволяют сразу видеть результат, поскольку холодный перезапуск — совсем не быстрый.В будущем я планирую поглубже поковырять эту штуку. Попробую реализовать любимые мной комбинаторы в каком-то приближении. Может быть постримлю процесс. А вы сходите на сайт фреймворка — там есть примеры, гораздо более впечатляющие, чем мои картинки
:)👍6🔥5💩1
Выложил таки то, что должно было стать материалом для книги про разные "*Scripts". Опубликовал мою часть, которая рассказывает про ClojureScript. Материала там не сильно много и в целом я не пытался написать книгу для новичков — предполагалось что-то вроде "Семи языков за семь недель", где от читателя тоже требовались известные навыки по поиску источников и некоторая самостоятельность.
Читайте, критикуйте, может быть и вырастим совместными усилиями что-то пристойное
Читайте, критикуйте, может быть и вырастим совместными усилиями что-то пристойное
:)🔥25👍3💩1
На днях подумалось, что было бы забавно скрестить "черепашку" со стеком состояний, что дало бы возможность рисовать те же папоротники, но без реализации L-system (собственно, при реализации последней стек состояний черепашки бы тоже пригодился).
Идею я сначала отложил до момента, когда хватит времени на то, чтобы засесть за Kotlin+OPENRANDR (см.выше). А сегодня утром внезапно захотелось уже прототип опробовать и я вспомнил про черепаху питоновскую. Да, она медленная и рисует без сглаживания, но зато REPL у IPython достаточен, чтобы прямо сразу результат прогона видеть.
Результат вы видите. Мне кажется, неплохо получилось для кода в пол-экрана
Идею я сначала отложил до момента, когда хватит времени на то, чтобы засесть за Kotlin+OPENRANDR (см.выше). А сегодня утром внезапно захотелось уже прототип опробовать и я вспомнил про черепаху питоновскую. Да, она медленная и рисует без сглаживания, но зато REPL у IPython достаточен, чтобы прямо сразу результат прогона видеть.
Результат вы видите. Мне кажется, неплохо получилось для кода в пол-экрана
:)
А ещё, поскольку turtle имеет состояние, можно прерывать рисование с помощью Ctrl-C и просить прямо от места останова построить новое дерево! Вот это сходу с чистыми L-systems сделать не получится, например. Зато это отличный способ добавить немного случайности в генеративное искусство!👍20🔥7
Так уж вышло, что я нынче опять на Python разрабатываю. И опять Web. Но, внезапно, на Pyramid! Да, бывает и такое!
Для тех, кто не застал (для этого нужно было удивительный мир питонов начинать изучать, как я, лет цать назад): это такой Web-фреймворк, который всегда был известен своей инаковостью, мол, "мы вам ничего не диктуем, делайте на нашей основе свою платформу!". По сути вам давали только маршрутизацию и систему прав (которая User Access Control), но, как говорится, "зато какие!". Сходите на домашнюю страничку проекта и почитайте хотя бы лозунги авторские — очень пафосно!
Так вот, если система контроля прав там развесистая, но в целом понятная, то маршрутизация сделана "максимально мощно". Никаких вам регулярок, каждый фрагмент пути, это некий ресурс, который решает, как обрабатывать дальнейшие фрагменты. Всё сделано на основе перегрузки протокола Mapping, то есть ресурсу скармливается фрагмент пути как ключ (
В простейшем случае вы можете все маршруты описать словарём. Однако, пирамидоголовые (можно ли их так называть?) любят строить настоящий динамический роутинг и гордятся своими постройками. А потом приходится, дабы понять, куда ведёт очередной
Я действительно могу видеть несколько потенциально оправданных применений такой маршрутизации. Например, в случае, когда путь описывает фактические файлы и директории, а система прав регулирует доступ к оным. Или если вы пишете штуку вроде Kinto — Generic JSON Storage, где возможны какие-то на лету создаваемые иерархии сущностей (Kinto — интересный проект, кстати, в том числе и как self-hosted штучка для непитонистов). А вот обычные CRUD делать на Pyramid не то чтобы как-то особенно удобно (точно не удобнее, чем на Django).
Я вообще сторонник того, чтобы можно было все маршруты увидеть разом. И даже если их скрипт выводит, пусть делает это без раскочегаривания подключений к базе и прочим шинам! И OpenAPI со Swagger тоже не заточены на динамическую маршрутизацию. Так что пусть
Вообще у меня нынче имеется стойкая тяга к фреймворкам: хочу типовые задачи решать типовыми же способами, в идеале (полу)автоматически. И мощь соотношу с покрытием рядовых случаев, а не с гибкостью для DIY (впрочем, потенциал для потенциальной модификации я тоже ценю). По крайней мере ощущаю такое в отношении CRUD backends.
Для тех, кто не застал (для этого нужно было удивительный мир питонов начинать изучать, как я, лет цать назад): это такой Web-фреймворк, который всегда был известен своей инаковостью, мол, "мы вам ничего не диктуем, делайте на нашей основе свою платформу!". По сути вам давали только маршрутизацию и систему прав (которая User Access Control), но, как говорится, "зато какие!". Сходите на домашнюю страничку проекта и почитайте хотя бы лозунги авторские — очень пафосно!
Так вот, если система контроля прав там развесистая, но в целом понятная, то маршрутизация сделана "максимально мощно". Никаких вам регулярок, каждый фрагмент пути, это некий ресурс, который решает, как обрабатывать дальнейшие фрагменты. Всё сделано на основе перегрузки протокола Mapping, то есть ресурсу скармливается фрагмент пути как ключ (
resource['users']), а тот либо возвращает новый ресурс, либо выбрасывает KeyError и маршрутизация останавливается (возвращается статус 404).В простейшем случае вы можете все маршруты описать словарём. Однако, пирамидоголовые (можно ли их так называть?) любят строить настоящий динамический роутинг и гордятся своими постройками. А потом приходится, дабы понять, куда ведёт очередной
PUT /v1/users/105/pets/4/barf, вызывать специальную программку pviews, которая выполнит маршрутизацию с хождением в базу и остальными побочными эффектами, возможными в пути, и вернёт ресурс и view, которые находятся в конце пути. Никакой PyCharm вам этого знания не даст, так и придётся в терминале спрашивать, а порой ещё и внутри Docker-контейнера. "Зато гибко!".Я действительно могу видеть несколько потенциально оправданных применений такой маршрутизации. Например, в случае, когда путь описывает фактические файлы и директории, а система прав регулирует доступ к оным. Или если вы пишете штуку вроде Kinto — Generic JSON Storage, где возможны какие-то на лету создаваемые иерархии сущностей (Kinto — интересный проект, кстати, в том числе и как self-hosted штучка для непитонистов). А вот обычные CRUD делать на Pyramid не то чтобы как-то особенно удобно (точно не удобнее, чем на Django).
Я вообще сторонник того, чтобы можно было все маршруты увидеть разом. И даже если их скрипт выводит, пусть делает это без раскочегаривания подключений к базе и прочим шинам! И OpenAPI со Swagger тоже не заточены на динамическую маршрутизацию. Так что пусть
/users/1/pets/2/barf говорит 404, если второй питомец у первого пользователя — не собака. Но маршруты /meow, /quack пусть у всех /pets/ будут!Вообще у меня нынче имеется стойкая тяга к фреймворкам: хочу типовые задачи решать типовыми же способами, в идеале (полу)автоматически. И мощь соотношу с покрытием рядовых случаев, а не с гибкостью для DIY (впрочем, потенциал для потенциальной модификации я тоже ценю). По крайней мере ощущаю такое в отношении CRUD backends.
🔥16
Сейчас опять про Python будет, но не только лишь про него.
Посмотрел на днях запись доклада "Async Django: The practical guide", чтобы слегка синхронизировать своё понимание темы с тем, как там оно сейчас. С одной стороны ничего нового лично я для себя не вычленил: сам фреймворк отлично себя чувствует в синхронной ипостаси, а любые штуки вроде поддержки WebSockets всё ещё прикручиваются сбоку через channels — я не говорю, что это плохо, кстати. А вот тем, кто именно ждёт подробностей о реализации или использовании, одного этого доклада может не хватить.
Чем же доклад интересен в том числе и для тех, кто с Python не работает? Тем, что взято в качестве примера, вокруг которого всё повествование строится. Докладчик показывает, как сделать Web Chat и добиться получения клиентом свежих сообщений аж четырьмя разными способами! Рассматриваются:
1. Обычные запросы обновлений по таймеру
2. Long polling
3. Server-Sent Events (SSE)
4. WebSockets
С первым пунктом всё понятно, и меня лично позабавило лишь то, что и в этом докладе про Django упоминается HTMX. Это вообще заметная и приятная лично для меня) тенденция — активно осваивать HTMX, применять в проектах на Django и рассказывать о своём опыте!
Long Polling — это уже классика, старая школа, ностальгия по DialUp. С использованием HTMX, опять же, делается легко и приятно. В довесок к Django уже нужны django-channels, но реализация всё ещё простая и прямолинейная.
SSE тоже сделаны через channels и тут было забавно посмотреть на то, как порции HTML освобождаются от переводов строк. Потому что SSE иначе не умеет, кроме как слать по строчке за раз. Unix shell style, практически!
С WebSockets всё понятно: нормальная посылка сообщений без дополнительной подготовки. Канал дуплексный, опять же, хоть в примере это свойство WS не используется.
И мне лично понравилось то, как автор предлагает слушателям, которым вдруг понадобится "чат написать", подумать, где на этой оси "синхронно и просто — асинхронно и сложно" остановиться! Не всем нужен дуплексный канал, кому-то и long polling хватит, третьих в принципе устроит обновление по таймеру, зато реализация будет простой и предсказуемой! Вот такие доклады я люблю
Посмотрел на днях запись доклада "Async Django: The practical guide", чтобы слегка синхронизировать своё понимание темы с тем, как там оно сейчас. С одной стороны ничего нового лично я для себя не вычленил: сам фреймворк отлично себя чувствует в синхронной ипостаси, а любые штуки вроде поддержки WebSockets всё ещё прикручиваются сбоку через channels — я не говорю, что это плохо, кстати. А вот тем, кто именно ждёт подробностей о реализации или использовании, одного этого доклада может не хватить.
Чем же доклад интересен в том числе и для тех, кто с Python не работает? Тем, что взято в качестве примера, вокруг которого всё повествование строится. Докладчик показывает, как сделать Web Chat и добиться получения клиентом свежих сообщений аж четырьмя разными способами! Рассматриваются:
1. Обычные запросы обновлений по таймеру
2. Long polling
3. Server-Sent Events (SSE)
4. WebSockets
С первым пунктом всё понятно, и меня лично позабавило лишь то, что и в этом докладе про Django упоминается HTMX. Это вообще заметная и приятная лично для меня) тенденция — активно осваивать HTMX, применять в проектах на Django и рассказывать о своём опыте!
Long Polling — это уже классика, старая школа, ностальгия по DialUp. С использованием HTMX, опять же, делается легко и приятно. В довесок к Django уже нужны django-channels, но реализация всё ещё простая и прямолинейная.
SSE тоже сделаны через channels и тут было забавно посмотреть на то, как порции HTML освобождаются от переводов строк. Потому что SSE иначе не умеет, кроме как слать по строчке за раз. Unix shell style, практически!
С WebSockets всё понятно: нормальная посылка сообщений без дополнительной подготовки. Канал дуплексный, опять же, хоть в примере это свойство WS не используется.
И мне лично понравилось то, как автор предлагает слушателям, которым вдруг понадобится "чат написать", подумать, где на этой оси "синхронно и просто — асинхронно и сложно" остановиться! Не всем нужен дуплексный канал, кому-то и long polling хватит, третьих в принципе устроит обновление по таймеру, зато реализация будет простой и предсказуемой! Вот такие доклады я люблю
:)👍17🔥1
Прочитал "Untyped Python: The Python That Was" от Армина нашего Ронахера. Рекомендую сходить и почитать — и не только тем, кто с Python сталкивается. Во мне, как говорится, "отзывается"!
И перекликается с гремовской "Beating the Average" — там тоже было про "мощь всего мира в наших руках!". Ронахер даже пишет: "the exceptional developer experience these languages offered" и "It required a bit of restraint and it required a slightly different way of programming, but it was incredibly productive." — ну очень по-лисперовски!
Интересно было бы почитать, что бы Армин написал, если бы в своё время нырнул в Clojure или даже в CL? И не подхватил бы он в этой временной ветви The Lisp Curse?
Возвращаясь к статье, отмечу несколько мест, которые прямо таки зацепили.
Это предложение завершает абзац о том, что в те времена можно было в голове удержать то, как работает интерпретатор Python, потому что оный тогда был относительно небольшим и простым. Понимаемо!
---
Тут Армин про свой Werkzeug говорит, наверняка. Лисперов такой штукой не удивить, но тогдашнего условного джависта, думаю, очень впечатляло!
---
Тоже такое ощущаю. Сложность переварить лично я могу, но только в силу опыта. Ронахер тоже может, я уверен, а имеет в виду ситуацию "в среднем". Но многовато стало всего. При этом, часто расширение сопровождается дублированием имеющихся возможностей, а не только лишь добавляет что-то новое…
---
Наконец, продублирую ронахеровский PS:
Про TS мне сказать особо нечего, поскольку толком его не использовал, а вот с первым предложением постскриптума соглашусь: мне тоже кажется, что зачастую овчинка не стоит выделки.
---
P.S. (этот уже мой): статья не утверждает, что типы плохи или хороши, в Python или где-либо ещё. Это запись в личном блоге, статья о личных же переживаниях. Мне понравилось читать и сопереживать. Как-то так.
И перекликается с гремовской "Beating the Average" — там тоже было про "мощь всего мира в наших руках!". Ронахер даже пишет: "the exceptional developer experience these languages offered" и "It required a bit of restraint and it required a slightly different way of programming, but it was incredibly productive." — ну очень по-лисперовски!
Интересно было бы почитать, что бы Армин написал, если бы в своё время нырнул в Clojure или даже в CL? И не подхватил бы он в этой временной ветви The Lisp Curse?
:)Возвращаясь к статье, отмечу несколько мест, которые прямо таки зацепили.
Without doubt I was able to understand everything between the code that I wrote, and the code that ran end to end.
Это предложение завершает абзац о том, что в те времена можно было в голове удержать то, как работает интерпретатор Python, потому что оный тогда был относительно небольшим и простым. Понимаемо!
---
I had a module that allowed me to attach remotely to the running interpreter and execute Python code on the fly to debug it.
Тут Армин про свой Werkzeug говорит, наверняка. Лисперов такой штукой не удивить, но тогдашнего условного джависта, думаю, очень впечатляло!
---
Modern Python can at times be impossible to comprehend for a developer. In a way in some areas we are creating the new Java. We became the people we originally displaced. Just that when we are not careful we are on a path to the world's worst Java.
Тоже такое ощущаю. Сложность переварить лично я могу, но только в силу опыта. Ронахер тоже может, я уверен, а имеет в виду ситуацию "в среднем". Но многовато стало всего. При этом, часто расширение сопровождается дублированием имеющихся возможностей, а не только лишь добавляет что-то новое…
---
Наконец, продублирую ронахеровский PS:
Python is in a spot now where the time spent for me typing it, does not pay dividends. TypeScript on the other hand tilts more towards productivity for me. Python could very well reach that point. I will revisit this.
Про TS мне сказать особо нечего, поскольку толком его не использовал, а вот с первым предложением постскриптума соглашусь: мне тоже кажется, что зачастую овчинка не стоит выделки.
---
P.S. (этот уже мой): статья не утверждает, что типы плохи или хороши, в Python или где-либо ещё. Это запись в личном блоге, статья о личных же переживаниях. Мне понравилось читать и сопереживать. Как-то так.
🔥6
В понедельник закончился очередной Advent of Code. И я во второй раз добрался до конца вовремя, без пропусков и задержек!
По ощущениям задачки этого года были проще в среднем, чем задачи двух-трёх предыдущих лет. И нельзя сказать, что я просто руку набил — реально простые попадались даже на третьей неделе.
Увы, нельзя сказать, что какое-то из заданий запомнится, как бывало в раньше. И опять же, это не следствие того, что я натренировался: встречались задачки на обычный поиск пути, казалось бы, но с интересным поворотом во второй части (лабиринт в форме тора с телепортами на другие слои реальности). А в этом году даже простых клеточных автоматов не было, не говоря уж о "Жизни", которая учитывала соседей в будущем и прошлом!
Зато в этот раз были две задачи, которые решались на Python, скажем, в десяток строк, включая разбор входных данных, просто потому, что для языка есть готовые библиотеки, делающие graph clustering или находящие решение для системы из девяти уравнений с шестью неизвестными. Ещё всякие Mathematica и Wolfram Alpha подходили, вот только это уже не "of Code" какое-то, на мой взгляд…
Я в этом году решал задачки на Scala — набивал руку, раз уж в работе теперь использую. С одной стороны ленивость Haskell местами бы очень пригодилась да и парсеры на megaparsec я писать умею хорошо, с другой отладчиком в Intellij Idea было приятно пользоваться. В целом я обошёлся стандартной библиотекой, комбинаторный парсер один раз только применил, но это обычное дело для AoC — давать возможность обходиться без специфичных решений. И тем больше меня расстроили те самые две задачки, которые я выше упоминал.
В любом случае AoC — уже привычная часть моей жизни. А это приятно — иметь что-то, что точно порадует под конец года!
По ощущениям задачки этого года были проще в среднем, чем задачи двух-трёх предыдущих лет. И нельзя сказать, что я просто руку набил — реально простые попадались даже на третьей неделе.
Увы, нельзя сказать, что какое-то из заданий запомнится, как бывало в раньше. И опять же, это не следствие того, что я натренировался: встречались задачки на обычный поиск пути, казалось бы, но с интересным поворотом во второй части (лабиринт в форме тора с телепортами на другие слои реальности). А в этом году даже простых клеточных автоматов не было, не говоря уж о "Жизни", которая учитывала соседей в будущем и прошлом!
Зато в этот раз были две задачи, которые решались на Python, скажем, в десяток строк, включая разбор входных данных, просто потому, что для языка есть готовые библиотеки, делающие graph clustering или находящие решение для системы из девяти уравнений с шестью неизвестными. Ещё всякие Mathematica и Wolfram Alpha подходили, вот только это уже не "of Code" какое-то, на мой взгляд…
Я в этом году решал задачки на Scala — набивал руку, раз уж в работе теперь использую. С одной стороны ленивость Haskell местами бы очень пригодилась да и парсеры на megaparsec я писать умею хорошо, с другой отладчиком в Intellij Idea было приятно пользоваться. В целом я обошёлся стандартной библиотекой, комбинаторный парсер один раз только применил, но это обычное дело для AoC — давать возможность обходиться без специфичных решений. И тем больше меня расстроили те самые две задачки, которые я выше упоминал.
В любом случае AoC — уже привычная часть моей жизни. А это приятно — иметь что-то, что точно порадует под конец года!
👍15🔥4
Мои первые компьютеры (оба от "Электроники", МС-1502 и БК 0010-01) имели встроенный интерпретатор BASIC. А вообще с BASIC я познакомился даже раньше, чем у меня появилась техника, позволяющая на нём писать: мама купила книжку со сказками про блоху PSET, колобка CIRCLE, злого колдуна CLS — прямо в тексте вперемешку с прозой приводились программки, анимирующие соответствующие сценки.
Где-то в то время, когда у меня уже были БК и МС и BASIC я более-менее освоил, мне в руки попались ксерокопии ксерокопий какой-то книги с играми, листинг каждой из которых не превышал пару страниц. Увы, какие-то страницы в копии отсутствовали и использованный диалект BASIC был не самым стандартным. Но кое-как я и через это продирался, вводил и отлаживал многие игры, заимствовал авторские приёмчики. Уже сильно позже я узнал, что тогда в моих руках была копия книги "BASIC Computer Games".
Все игры работали в текстовом режиме, но кое-какие умели таки показывать интерфейс. Одной из самых продвинутых была игра Super Star Trek), известная и за пределами упомянутой книги. Эту игру воплощали буквально для любых систем, настолько концепция была удачна. Были даже коммерческие реализции. Недавно смотрел ролик про одну из таких реализаций: EGA Trek. Это достаточно продвинутая версия с приличным количеством дополнений к базовой игре, очень советую посмотреть, во что играли люди когда-то :)
Кстати, в сами игры из книги нынче можно в браузере поиграть: https://github.com/coding-horror/basic-computer-games/ — вот тут народ воспроизводит их на разных языках.
P.S. Когда смотрел обзор EGA Trek подумал, что именно в таком виде игру можно было бы воплотить "в железе": светодиодные матрички, семисегментные индикаторы, аналоговые "показометры", никаких ЖК-экранов, Arduino вместо мозгов.
Где-то в то время, когда у меня уже были БК и МС и BASIC я более-менее освоил, мне в руки попались ксерокопии ксерокопий какой-то книги с играми, листинг каждой из которых не превышал пару страниц. Увы, какие-то страницы в копии отсутствовали и использованный диалект BASIC был не самым стандартным. Но кое-как я и через это продирался, вводил и отлаживал многие игры, заимствовал авторские приёмчики. Уже сильно позже я узнал, что тогда в моих руках была копия книги "BASIC Computer Games".
Все игры работали в текстовом режиме, но кое-какие умели таки показывать интерфейс. Одной из самых продвинутых была игра Super Star Trek), известная и за пределами упомянутой книги. Эту игру воплощали буквально для любых систем, настолько концепция была удачна. Были даже коммерческие реализции. Недавно смотрел ролик про одну из таких реализаций: EGA Trek. Это достаточно продвинутая версия с приличным количеством дополнений к базовой игре, очень советую посмотреть, во что играли люди когда-то :)
Кстати, в сами игры из книги нынче можно в браузере поиграть: https://github.com/coding-horror/basic-computer-games/ — вот тут народ воспроизводит их на разных языках.
P.S. Когда смотрел обзор EGA Trek подумал, что именно в таком виде игру можно было бы воплотить "в железе": светодиодные матрички, семисегментные индикаторы, аналоговые "показометры", никаких ЖК-экранов, Arduino вместо мозгов.
🔥21👍2