Telegram Web Link
Несмотря на то, что по Scala достаточно множество книжек для начинающих, литературы уровня "advanced" не очень много. Однако год назад вышла книга Дениса Калинина, содержащая продвинутые рекомендации по программированию на Scala с прикладным уклоном (включает в том числе начала теории категорий).
https://leanpub.com/mastering-advanced-scala
Примерно на том же уровне находится книга Scala with cats, объясняющая, наоборот, общие абстракции из библиотеки cats. Книг на самом деле две - вторая представляет из себя сборник упражнений по материалу первой.
https://underscore.io/books/scala-with-cats/
Данная библиотека - наглядный пример того, как Scala можно использовать для написания действительно нужных dsl, в данном случае для уже богатой возможностями библиотеки для работы с БД doobie. Несмотря на плюсы в виде гарантированной статической типизации и удобной композиции запросов в транзакции, doobie обладает достаточно серьёзным недостатком - отсутствием удобных инструментов для создания запросов, вследствие чего их приходится писать вручную, либо создавать собственное решение. Представленный dsl позволяет сохранить все преимущества doobie и вместе с тем избавить программистов от необходимости использования raw-SQL запросов.
https://github.com/Hydrospheredata/typed-sql
Скорее всего, идея сделать Haskell на jvm назревала ещё до первого стабильного релиза оного, но до сих пор подобные языки явно не выходили из стадии экспериментальных проектов. А теперь такой язык есть - Eta, самый настоящий Haskell в экосистеме java-машины. В числе главных черт есть даже совместимость с Java!

На сайте проекта можно ознакомиться с синтаксисом и документацией языка, а также пройти ознакомительный тур. Для тех, кто уже созрел писать на Eta в IDE, есть плагин в IDEA от создателей языка.

https://eta-lang.org/docs/user-guides/eta-user-guide/introduction/what-is-eta
Короткий туториал по одной из самых быстрых Scala-библиотек для асинхронных задач monix от её создателя. Библиотека обладает богатым инструментарием для композиции задач, смены контекста их выполнения, контроля выделенных ресурсов и шедулинга. В видео рассмотрены ключевые функции и подходы к управлению ресурсами с использованием monix.
https://vimeo.com/299313903
Алгебры являются одним из наиболее важных понятий в функциональном программировании, имеющих при этом непосредственную реализацию в коде программы. В рамках данной лекции рассматриваются основные виды алгебр и примеры их использования в проектах.
https://www.youtube.com/watch?v=s2ay9nEW3ak
Несмотря на то, что ФП-концепции естественным образом ложатся на преобразования абстрактных данных и композицию вычислений, с нуля сложно представить, каким образом с помощью монад и алгебр можно сделать типовой веб-сервис, взаимодействующий с БД.

Хорошим примером являются следующие два sample-проекта: Todo service и Scala Pet store, написанные в достаточно строгом функциональном стиле.

https://github.com/jaspervz/todo-http4s-doobie

https://github.com/pauljamescleary/scala-pet-store
Достаточно интересная по концепции библиотека, позволяющая создание спецификации кода как композиции текста и иллюстративных примеров/тестов. specs2 обладает очень большой описательной способностью благодаря встроенному интерполятору, также присутствует интеграция с библиотеками Mockito и Scalacheck.

https://github.com/etorreborre/specs2
Развлекательной Скалы пост: существует твиттер (и соответствующий сайт) с высококачественными мемами на тему языков Scala и Haskell. Помимо, непосредственно, мемов в подборке встречаются также картинки-напоминания с основными особенностями (type-)классов библиотек cats, cats-effect и fs2.

https://impurepics.com/
Одним из наиболее важных качеств функциональных языков является их лаконичность и выразительность, что позволяет сконцентрироваться на решении задачи, а не на синтаксисе языка.
Рассмотрим, к примеру, классическую задачу получения n первых чисел в последовательности Фибоначчи и вывода их на экран.
(Важно: в задаче не учитываются ограничения на размер численных типов данных - на самом деле даже long исчерпывается достаточно быстро (~92 число Фибоначчи)).

Вариант №1 - императивный (Java <6).
Всё просто - классическое создание массива необходимого размера и его последующее заполнение. При этом требуется дополнительная логика проверки входных значений.
Печать в консоль также производится с помощью итерации по элементам массива.
Примечательно, что Java позволяет создавать массивы нулевой длины, так что этого типа данных достаточно для выполнения данной задачи.

https://gist.github.com/J0kerPanda/8ff3475b10bdc4e7a986322daf94a90c

Вариант №2 - рекурсивный (Java 8).
Перепишем данную функцию с использованием рекурсии. Поскольку для итераций необходим аккуммулятор значений, необходимо
вынести рекурсивную логику в отдельную вспомогательную функцию. В связи с тем, что Java не позволяет объявлять вложенные функции,
её необходимо объявить на том же уровне, что и основную, что затрудняет чтение кода. Сама функция, несмотря на рекурсивную природу,
слабо отличается от предыдущей в виду аналогичной логики, построенной на if, else. При этом, Java не оптимизирует хвостовую рекурсию,
поэтому при больших n вызов данной функции приведёт к переполнению стэка, чего не случилось бы в случае с циклом.
Стоит также отметить, что данная функция возвращает список в обратном порядке, поэтому, при необходимости, его необходимо инвертировать.
Для печати используется метод класса List - forEach, применяющий функцию System.out::println, переданную в качестве аргумента, к каждому значению в списке.

https://gist.github.com/J0kerPanda/c0057ef5d9c823f47ef068a822946f67

Вариант №3 - рекурсивный (Scala).
В данном случае, для непосредственного вычисления списка чисел Фибоначчи используется внутренняя функция inner, полностью зависящая только от своих аргументов.
Она хорошо отражает рекурсивную структуру базового алгоритма, а вставка начальных значений органично объединяется с основным случаем при помощи pattern-матчинга.
В данном случае вспомогательная функция изолирована от остального кода. При этом, поскольку Scala оптимизирует хвосторекурсивные вызовы, эффективность работы
данной функции сопоставима с циклом.
Числа Фибоначчи, как и в предыдущем случае, следуют в обратном порядке, а вывод также использует метод foreach.

https://gist.github.com/J0kerPanda/8e965ef34003ce3bcb23da98f27d8adc

Вариант №4 - потоковый (Scala)

Предыдущие примеры были написаны целиком с использованием функций для генерации списков чисел Фибоначчи. Однако, если вспомнить о математической природе задачи,
эти числа представляют собой бесконечную последовательность, подчинённую определённому закону. Естественным способом реализации бесконечных последовательностей
в функциональном программировании являются потоки (Stream).
Если представить себе поток пар чисел Фиббоначи (числа в паре упорядочены по возрастанию), то каждая последующая пара может быть получена из предыдущей из
наибольшего элемента предыдущей пары и суммы элементов предыдущей пары. Это, в свою очередь, позволяет получать необходимый список n чисел Фибоначчи как взятие n
элементов данного потока с последующей декомпозицией каждой пары в свой наибольший элемент. Код для получения такого потока занимает одну строчку.

val s  = 1 #:: Stream.iterate((1, 1)) { case (n1, n2) => (n2, n1 + n2) }.map(_._2)

...

s.take(n).foreach(println)

Вариант №5 - потоковый (Haskell)

Можно ли ещё короче? Haskell позволяет уложиться в 27 символов, но этот код менее понятен, чем предыдущий вариант, и требует понимания работы как библиотечной функции scanl, так и самого Haskell.

fibs = 1 : scanl (+) 1 fibs
Какой подход лучше?
anonymous poll

Потоковый (Scala) – 8
👍👍👍👍👍👍👍 73%

Императивный (Java) – 1
👍 9%

Рекурсивный (Java) – 1
👍 9%

Потоковый (Haskell) – 1
👍 9%

Рекурсивный (Scala)
▫️ 0%

👥 11 people voted so far.
Channel name was changed to «Scala bin»
Поскольку новая заметка вышла достаточно объёмной, да и переключаться на код из телеграма не очень удобно, решил попробовать следующий формат - всё, что не умещается в одно телеграм-сообщение публиковать на сайте, а мелкие заметки оставить в рамках канала.

Посмотреть на то, что получилось, можно по ссылке:

https://j0kerpanda.github.io/2018/11/24/algebraic-data-types.html
Насколько подходит новый формат?
anonymous poll

Всё как надо - статьи в блог, мелкие заметки в канал – 6
👍👍👍👍👍👍👍 100%

Новый формат нужен, но текущий вариант не подходит
▫️ 0%

Канал подходит для всего, ничего больше не нужно
▫️ 0%

👥 6 people voted so far.
Яркий пример того, что ФП не всегда приводит к максимальной лаконичности, в одной картинке.

N.B. Такой подход взамен предлагает получать всю информацию о том, что происходит в функции, по сигнатуре.
Отличная заметка про "best-practices", как в Scala, так и вообще в программировании. Также упоминаются достаточно интересные тонкости языка - готов поспорить, вы не знали, что явный return во вложенной анонимной функции реализован через выкидывание исключения (поэтому никогда не используйте его в Scala).

https://github.com/alexandru/scala-best-practices/blob/master/sections/2-language-rules.md
К разговору об особенностях языка: многие знают, что for-comprehensions в Scala - просто синтаксический сахар вокруг map и flatMap. Тем не менее, важно помнить, что каждая такая операция - это дополнительная аллокация (а в for-comprehensions по умолчанию добавляется дополнительный map в конце). При этом любая декомпозиция объектов (например, for { Dummy(v) <- Some(Dummy(v)) } yield v) требует наличия метода withFilter, который не для каждой структуры может быть реализован в принципе.

Устраняет эти проблемы scala-plugin от Олега Пыжова, который часто подключают в проекты по умолчанию.

Больше примеров for-comprehensions в Scala тут и тут.
Довольно часто в сигнатурах функций и классов в Scala можно увидеть что-то вроде def func[F[_]](...), что у многих поначалу вызывает затруднения при чтении соответствующего кода. Данная конструкция делает следующий шаг в параметризации типов: func[F[_]](...) - это функция, параметризованная типом, который, в свою очередь, тоже зависит от некоторого типового параметра. Предпосылки этой абстракции лаконично (особенно для первого знакомства) описаны в следующей статье.
На правах неоплачиваемой рекламы: достаточно большое число людей начинает знакомство со Scala с курсов на Сoursera или книжек от Мартина Одерски. Теперь появился ещё один весьма интересный способ приступить к изучению языка - коллекция интерактивных примеров на Jupyter. Для взаимодействия с ними нужен только браузер, а сам материал материал подан очень качественно и подробно.

https://hub.mybinder.org/user/sbrunk-almond-examples-3zsmyq6n/lab
Для более опытных скалистов также вскоре откроется новый курс, в создании которого принял участие уже упомянутый Мартин Одерски - создатель языка Scala. Онлайн-курс начинается в феврале и посвящен реактивному программированию. Он включает в себя как общие концепции, так и их реализацию на Scala с помощью фреймворка Akka. Изучение материалов абсолютно бесплатно, однако за скромные 50$ можно проспонсировать создателей курса и платформу, а также получить приятный сертификат в резюме.

https://www.edx.org/course/programming-reactive-systems
2025/07/04 06:14:48
Back to Top
HTML Embed Code: