Pull to refresh
60
1
Михаил Потанин@potan

Функциональный программист

Send message

Как управлять миром с помощью Nu

Level of difficultyEasy
Reading time4 min
Reach and readers9.1K

Даже сравнительно простой мир, такой как ArtifactoryMMO, приподносит не мало неожиданностей. Хотя есть много примеров кода для управления этим миром из Javascript и Python, я выбрал более серьезный язык, расчитывая прикрутить туда какие-нибудь интересные алгоритмы машинного обучения. Но все равно слишком часто, по крайней мере при отладке, приходится отдавать отдельные команды и анализировать что получилось вручную. Несмотря на прекрасный REPL в Julia, один из лучших, что мне доводилось использовать, и для отладки своего кода, и просто как калькулятор, здесь это оказалось не очень удобно. Конечно, есть curl и jq, но по эргономичности он тоже не идеален. Не curl-ом единым, удобный HTTP-клиент встроен, например, в PowerShell. Но мне захотелось чего-то нового и прогрессивного, и я решил посмотреть Nu. Эта статья предназначена, чтобы привлечь к этому shell любителей MMO-игр, и заинтересовать MMO-играми пользователей nu-shell, а если повезет, заинтересовать обоими темами тех, кто раньше про них и не знал.

Читать далее

Возвратиться или продолжить: поговорим про continuations

Level of difficultyMedium
Reading time6 min
Reach and readers9.5K

Одна из самых эзотерических тем в программировании и computer science это продолжения (continuations), ограниченные продолжения (delimited continuations) и continuation-passing style. Я попытаюсь раскрыть эту тему понятным для обычного программиста языком. Предполагается, что обычный программист знаком с понятиями функции/подпрограммы, фрейма вызова (stack frame), а также имеет базовое знания языка Scheme, хотя бы на уровне первых глав SICP.

Читать далее

Prolog in Prolog: зачем и как

Reading time9 min
Reach and readers5K

Язык Prolog создавался для задач иссуственного интеллекта, который сейчас обычно называют "классическим", чтобы не путать с задачами машинного обучения путем подбора большого числа числовых параметров. Важным классом таких задач является моделирование "мира", в котором можно совершать какие-либо действия. Игрушечным примером такого мира является Nani Search. И решают их часто в таком стиле: состояние мира помещается в прологовскую базу данных и все изменения производятся путем удаления и добавления фактов в это хранилище. Но это получается уже не логическое программирование, а самое настоящее императивное! При этом используются худшие практики программирование - глобальное состояние! Мимо этого я пройти не могу!

Но самое плохое в таком подходе не стиль, в конце концов большая часть современного кода императивна, и даже частенько использует, явно или неявно, глобальные переменные. Важно что состоятние мира перестает быть first-order value и пропадает возможность решать задачи в моделируемом мире, для чего и создавался язык Prolog.

Читать далее

Сегментная адресация памяти

Reading time7 min
Reach and readers13K

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

В подавляющем большинстве компьютерных систем для работы с некоторой ячейкой памяти необходимо как-то указать ее адрес, как правило 16-, 32- или 64-разрядное число. Количество бит в адресе часто называют разряностью системы. Часто дополнительно используется механизм "трансляции страниц", который отображает области виртуальной памяти пользовательского приложения в физическую память, которой управляет операционная система. Но в каждый момент времени активна отлько одна "таблица страниц" и с точки зрения приложения (а во многом и с точки зрения ядра ОС) память остается плоской.

Рассмотрим старый процессор Intel 86/88/186. Размер регистров этих процессоров всего 16 бит, что позволяет адресовать всего 64 килобайта памяти. Когда эти микросхемы разрабатывались, такого размера памяти уже не хватало для многих приложений, а 32-разрядные процессора были слишком дороги. Проблему решили добавив в архитекруту сегментные регистры. При обращении к памяти к 16-битному адресу (хранящемуся в реристре общего назначения или прямо в коде команды) прибавлялось значение сегментного регистра, сдвинутое на 4 бита (что тоже самое, умноженное на 16) и полученное значение использовалось как физический адрес. Такой подход позволял адресовать до одного гигабайта памяти. В архитектуре персональных компьтерах IBM PC, созданных на базе этих процессров, часть адресного пространства было зарезервировано для системных нужд, а пользовательским приложениям и ОС было доступно до 640 килобайт. Но не все так просто.

Читать далее

Как я начал писать макросы для Rust на Gluon

Reading time2 min
Reach and readers4.4K

Во многих языках есть специальный механихм для кодогенерации - макросы. Иногда из реализуют на отдельном достаточно примитивном языке, основанном на простой подстановке текста (препроцессоры PL/I и C, m4), но даже в таком варианте удается делать интересные и полезные вещи. Другой популярный вариант - макросы реализуются на том же языке, что и программа, в которой они используются. Такой подход ведет свое начало из Lisp (удобный тем, что формат программ и данных там одинаков), активно применяется в Julia, OCaml(camlp4/5), Scala, Haskell, Rust, а наибольшего развития получил в Nemerle, где макрос может может запускаться как до, так и после проверки и вывода типов, и в последнем варианте иметь доступ к типам.

При этом макросах все возможности языка не нужны, скажем высокая эффективность и безопасность Rust пользы здесь не принесут и могут только затруднить разработку.

Читать далее

Особенности обновлений узлов децентрализованных блокчейн-систем

Reading time4 min
Reach and readers1.7K
Вопросы управления изменениями сами по себе достаточно сложны. Но при обновлении программного обеспечения распределенной систем, узлы которых принадлежат различным зонам ответственности, какими являются большинство блокчейн-систем возникают специфические не интуитивные проблемы, про которые иногда забывают даже опытные разработчики. Эта статья написана в некотором смысле как шпаргалка, что бы самому реже про эти тонкости забывать
Читать дальше →

Очередной подход к RS-триггеру, теперь с TLA+

Reading time4 min
Reach and readers3K
Я уже моделировал RS-триггер как полностью синхронную схему. Но в некоторых приложениях таких моделей не достаточно, требуется рассмотреть переходные процессы, которые могут возникнуть. TLA+ разработан для анализа параллельных асинхронных систем. Поупражнявшись в решении головоломок с его помощью, можно начать применять этот инструмент и для более серьезных задач.
Читать дальше →

How to Catch a Cat with TLA+

Reading time3 min
Reach and readers2.1K
Many programmers struggle when using formal methods to solve problems within their programs, as those methods, while effective, can be unreasonably complex. To understand why this happens, let’s use the model checking method to solve a relatively easy puzzle:

Conditions


You’re in a hallway with seven doors on one side leading to seven rooms. A cat is hiding in one of these rooms. Your task is to catch the cat. Opening a door takes one step. If you guess the correct door, you catch the cat. If you do not guess the correct door, the cat runs to the next room.
Read more →

Ловим кота с TLA+

Reading time4 min
Reach and readers8.6K
Формальные методы считаются эффективным, но неоправданно сложным способом обеспечения надежности программного обеспечения. Используемые при этом инструменты существенно отличаются от привычных программисту. Эта статья написана с целью снизить порог вхождения в этот инструментарий. Я применю систему model checking не для решения сложно формулируемых задач спецификации ПО, а для решения понятной даже школьникам головоломки.

Вы находитесь в прямом коридоре с семью комнатами по одну сторону. В одной из них находится кот. За один шаг можно заглянуть в одну из комнат, если там есть кот, он пойман. Как только дверь закроется, кот перейдет в одну из соседних комнат к той, в которой находился. Задача — поймать кота.
Читать дальше →

Паттерн Model-Update-View и зависимые типы

Reading time13 min
Reach and readers11K


Model-Updater-View — функциональный паттерн, успешно применяемый в языке Elm в основном для разработки пользовательских интерфейсов. Что бы им воспользоваться надо создать тип Model, представляющий полное состояние программы, тип Message, описывающий события внешней среды, на которые программа должна реагировать, меняя свое состояние, функцию updater, которая из старого состояния и сообщения создает новое состояние прораммы и функции view, которая вычисляет по состоянию программы требуемые воздействия на внешнюю среду, которые порождают события типа Message. Паттерн очень удобный, но у него есть маленький недостаток — он не позволяет описать какие события имеют смысл для конкретных состояний программы.

Схожая проблема возникает (и решается) и при использовании ОО-паттерна State.

Язык Elm простой, но очень строгий — он проверяет, что функция updater хоть как-то обрабатывает все возможные сочетания модели-состояние и сообщения-события. По этому приходится писать лишний, пусть и тривиальный — как правило оставляющий модель без изменений, код. Я хочу продемонстрировать, как этого можно избежать в более сложных языках — Idris, Scala, C++ и Haskell.
Читать дальше →

ROS, ELM и черепашка

Reading time6 min
Reach and readers6.6K
Robotic Operation System позволяет взаимодействовать своим подсистемам по механизмам «подписка на топик» и «вызов сервиса» по своему специальному протоколу. Но есть пакет rosbridge, который позволяет общаться с ROS извне с помощью websocket. Описанный протокол позволяет выполнять основные операции по взаимодействию с другими подсистемами.

ELM — очень простой и элегантный язык, компилирующийся в javascript и отлично подходящий для разработки интерактивных программ.

Я решил совместить приятное с полезным и изучать ROS (по которой сейчас идет курс) и ELM вместе.
Читать дальше →

Функциональные языки в разработке аппаратуры

Reading time8 min
Reach and readers15K
Функциональные языки, как правило, не слишком подходят для низкоуровнеого программирования, хотя и применяются для кодогенерации.

Примеры проектов
генерация безопасного кода на C (используется в лаборатории Касперского) Ivory, поддержка реактивного программирования на Arduino, и так далее Atom, Ion

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

Моделирование кинематики — это не сложно

Reading time5 min
Reach and readers14K
Мне давно хочется заняться созданием роботов, но всегда не хватает свободных денег, времени или места. По этому я собрался писать их виртуальные модели!

Мощные инструменты, позволяющие это делать, либо сложно стыкуются со сторонними программами (Modelica), либо проприетарны (Wolfram Mathematica, различные САПР), и я решил делать велосипед на Julia. Потом все наработки можно будет состыковать с сервисами ROS.

Будем считать, что наши роботы двигаются достаточно медленно и их механика находится в состоянии с наименьшей энергией, при ограничениях, заданных конструкцией и сервоприводами. Таким образом нам достаточно решить задачу оптимизации в ограничениях, для чего понадобятся пакеты "JuMP" (для нелинейной оптимизации ему понадобится пакет "Ipopt", который не указан в зависимостях (вместо него можно использовать проприетарные библиотеки, но я хочу ограничится свободными) и должен быть установлен отдельно). Решать дифференциальные уравнения, как в Modelica, мы не будем, хотя для этого есть достаточно развитые пакеты, например "DASSL".

Управлять системой мы будем используя реактивное программирование (библиотеку "Reactive"). Рисовать в «блокноте» (Jupyter), для чего потребуются "IJulia", "Interact" и "Compose". Для удобства еще понадобится "MacroTools".
Для простоты рассмотрим 2D робота, сделанного из веревок и пружин

Из командной строки за знаниями

Reading time4 min
Reach and readers7.3K

Один из наиболее распространенных стандартов работы с базами знаний являются представление RDF и язык запросов SPARQL. Доступ к базе обычно осуществляется через SPARQL-endpoint по протоколу HTTP (Jena и Sesame могут использоваться как встраиваемые базы, например через обертку banana-rdf, а к Virtuoso можно обращаться так же по ODBC, добавив к строке запроса префикс 'SPARQL ').
Есть много открытых «точек доступа SPARQL» — по wikipedia DBpedia, большой набор биологических баз знаний, геоданные.
К endpoint, как правило, прилагается web-интерфейс, но браузер — это слишком громоздко, и мы хотим обращаться к ним напрямую из командной строки!
Читать дальше →

PowerShell, AWS CLI и json

Reading time3 min
Reach and readers7.5K
При работе с облаком Amazon, часто приходится выполнять много рутинных операций через Web консоль. Но хочется их автоматизировать.
AWS CLI, интерфейс командной строки, хорошо для этого подходит. Конечно, можно написать и приложение на Scala, но в повседневных задачах лучше обойться без «тяжелой артиллерии».
Команды AWS умеют возвращать данные в разных форматах, в том числе и в json. Можно воспользоваться bash и jq, но последнего нет в репозитарии cygwin, а руками устанавливать лень. Между тем в PowerShell есть прекрасная поддержка json! Правда оказалось, что воспользоваться этим не совсем просто.
Читать дальше →

Развлечения на плоскости Лобачевского

Reading time2 min
Reach and readers15K
Евклидова плоскость скучна. Доступное пространство растет всего лишь как квадрат радиуса обзора. По сравнению с ней просторы плоскости Лобачевского гигантски. Но и там есть жизнь!
Сумма углов многоугольника здесь меньше, чем у Евклида и не постоянна, а зависит от площади (от сюда интересное следствие — существуют самые большие треугольники, четырех- пяти- и тп угольники, сумма углов который становится равной нулю). По этому существуют замощения плоскости любыми правильными многоугольниками, если они достаточно велики. В статье про игру Жизнь используется замощение четырехугольниками, в каждой вершине сходятся по пять четырехугольников. Но такие четырехугольники очень велики. Если отказаться от одинаковости многоугольников, можно взять замощение из правильных шести- и семиугольников. Для него можно изготовить наглядную модель плоскости из магнитных шариков «Неокуб».
Читать дальше →

Решетчатое наследование

Reading time4 min
Reach and readers8.5K
Наследование, при кажущейся простоте, часто приводит к сложным, сопротивляющимся изменениям структурам. Иерархии классов растут как самый настоящий лес.
Целью наследование является привязка кода (набора методов) к минимальному набору свойств сущности (как правило — объекта), которые он обеспечивает и которые ему требуются. Это упрощает повторное использование, тестирование и анализ кода. Но наборы свойств со временем становятся очень большими, начинают пересекаться нетривиальным образом. И в структуре классов появляются миксины и прочее множественное наследование.
Внести изменения в глубине иерархии становится проблематично, приходится думать заранее о «внедрении зависимостей», разрабатывать и использовать сложные инструменты рефакторинга.

Возможно ли всего этого избежать? Стоит попытаться — пусть методы будут привязаны к множеству характерных свойств объекта (тегов), а иерархия наследования выстраивается автоматически по вложенности этих множеств.

Пусть мы разрабатывает иерархию для игровых персонажей. Часть кода будет общая для всех персонажей — она привязана к пустому набору свойств. Код, отвечающий за их отображение будет представлен в виде вариантов для OpenGL и DirectX разных версий. Что-то будет зависеть от расы персонажа, что-то от наличия и вида магических способностей и тп. Теги персонажа первичны. Они перечисляются явно, а не наследуются. А реализация наследуется в зависимости от набора тегов (по вложенности). Таким образом умение стрелять из ПЗРК не окажется у кенгуру, потому что его унаследовали от пехотинца.

Идея такого подхода была предложена Дмитрием Кимом. Автор не стал ее воплощать в код, я попробую исправить это упущение.
Реализация такого подхода на Clojure, как обычно, на github.
Читать дальше →

Pattern matching с помощью макросов

Reading time4 min
Reach and readers5.7K
Язык Julia не поддерживает такую технику программирования, хорошо зарекомендовавшую себя в языках Haskell, Prolog, Erlang, Scala, Mathematica, как pattern matching. Но разрешает писать макросы, которые позволяют исправить этот фатальный недостаток. Выглядит это примерно так:
julia> immutable X a end

julia> immutable Y a ; b end

julia> @case(Y(X(9),2),  Y(4,3)-> 55, Y(X(k),2)->1+k)
10

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

Наследование комбинаторных парсеров на Julia

Reading time7 min
Reach and readers6.6K
Комбинаторные (монадические) парсеры достаточно хорошо известны (wikibooks). Они представляют из себя библиотеку маленьких парсеров, которые распознают простые элементы грамматики, и способы объединять несколько парсеров в один (комбинировать — от сюда и название). Монадические они потому что один из способов комбинирования, порождения парсера остатка текста на основе результата разбора начала, удовлетворяет условиям, накладываемым на математический объект «монада». В языке Haskell это позволяет воспользоваться мощным сервисом, предоставляемым языком и библиотеками. В других языках название «монадические» можно смело игнорировать — это не будет мешать их реализации и использованию, включая упомянутую выше операцию «bind».

Проще всего комбинаторные парсеры реализуются в языках с поддержкой замыканий, но можно воспользоваться и классическим ООП (пример описан Rebecca Parsons в книге Мартина Фаулера «Предметно-ориентированные языки»).
К преимуществам комбинаторных парсеров относится простота использования (запись на языке программирования практически не отличается от обычного описания грамматики), независимость от препроцессора (как yacc/bison, happy или ocamlyacc), возможность реализовать некоторые элементы, плохо укладывающиеся в контекстно-свободную грамматику, прямо на языке программирования общего назначения.

К недостаткам — сложность составления сообщений об ошибке, неспособность работать с леворекурсивной грамматикой (приводит к зацикливанию), а так же то, что очень легко сделать этот парсер не эффективным по быстродействию и памяти. (Одна из причин — компилятор не может произвести оптимизацию в терминах грамматики, так как работает на уровне языка программирования. Но есть и другие тонкости, требующие внимания, если требуется эффективность.)
Как альтернативу можно рассмотреть реализации в виде макросов (например OCaml streams parsers). В Perl6 поддержка грамматик встроена в язык.

Наследование

Персер конкретного языка состоит из множества более специализированных парсеров, ссылающихся друг на друга. В этом отношении парсеры напоминают методы некого объекта. Возникает желание порождать парсеры новых версий языков, подменяя отдельные подпарсеры (как это делается в паттерне проектирования «шаблонный метод» из ООП). Для экспериментов с этим подходом (а так же в порядке изучения очередного языка) я выбрал язык Julia — динамически-типизированном с особым подходом к наследованию (подобному CLOS из Common Lisp и R).
В отличие от обычных комбинаторных парсеров, подход с наследованием является экспериментальным (хотя в некотором виде поддерживается библиотекой макросов OCaml и языком Perl6). Пока он порождает не очень читабельный код. Исходный код доступен на Github.
Читать дальше →

Числовые классы типов в Rust

Reading time6 min
Reach and readers11K
Абстракции Rust отличаются от привычных в ООП. В частности вместо классов (классов объектов) используются классы типов, которые называются «trait» (не следует путать с trait из Scala, где под этим термином прячутся примеси — mixin).
Классы типов не уникальны для Rust, они поддержаны в Haskell, Mercury, Go, из можно реализовать слегка извращенным способом на Scala и C++.

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

Интерфейсы числовых типов довольно громоздки, и я буду вставлять здесь только фрагменты кода. Весь код доступен на github (Update: работающая версия доступна на crates.io).
Большинство реализованных здесь интерфейсов имеют статус experemental или unstable и скорее всего будут меняться. Я постараюсь поддерживать код и текст актуальными.

Rust поддерживает перегрузку операций, но, в отличие от C++, у операций есть метод-синоним с обычным буквенным именем. Так a+b может быть записано a.add(b), а для переопределения операции '+' надо просто реализовать метод add.

Что же такое - класс типов?
1

Information

Rating
1,957-th
Works in
Registered
Activity

Specialization

Бэкенд разработчик
Git
SQL
Английский язык
Linux
Scala
Haskell
Функциональное программирование