Конспект по Scala with Cats

Scala with Cats – это свободно доступная книга, написанная Noel Welsh и Dave Gurnell из Underscore. Охватывает все основы использования библиотеки cats.

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

Ниже краткий насколько возможно конспект по Type Class'ам из книги.

Show

  • вывести на печать любой тип
  • syntax: .show

Eq

  • типобезопасное сравнение
  • syntax:
    • a === b
    • a =!= b

Monoid

  • операции
    • .combine(a1, a2)
    • .empty[A]
  • законы:
    • combine ассоциативный
    • empty должен быть нейтральным элементом (identity element)

Semigroup

  • объединение двух значений
  • только combine из Monoid
  • там где требуется Semigroup, всегда можно использовать Monoid
  • нужен так как не всегда существует нейтральный элемент, пример – NonEmptyList
  • syntax: a |+| b

Functor

  • что-то у чего есть map
  • не стоит думать об этом только, как о проходе по списку, это может быть и работа с внутренним состоянием "контейнера" (в контексте этого "контейнера"), без извлечения значения из "контейнера".
  • операции:
    • .lift(f)
  • syntax:
    • f.map(g)

Contravariant (Functor)

  • из F[B] имея A => B получить F[A]
  • syntax: .contramap(f)

Invariant

  • имея A => B, B => A и Monoid[B] получить Monoid[A]
  • syntax: Monoid[B].imap(f)(g)

Monad

  • 1000 разных подходов к определению, в книге такое: монада – механизм для последовательных вычислений
  • операции
    • .pure(a) – создание монадического контекста из сырого значения
    • .flatMap(f) – извлечение значения из контекста и создание следующего контекста в последовательности
  • любая монада – функтор, map легко построить из pure+flatMap
  • laws:
    • левоассоциативность: pure(a).flatMap(f) == f(a). тут важно помнить об эффектах. именно по этой причине Try не Monad, так как если "снять" с него контекст монады при обычном вызове получим эффект – исключение, а если не снять то получим Failure.
    • правоассоциативность: m.flatMap(pure) == m.
    • ассоциативность: m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))
  • syntax:
    • .pure[T] (из cats.syntax.applicative)
    • .map(f) (из cats.syntax.functor)
    • .flatMap(f) (из cats.syntax.flatMap)
    • можно использовать for comprehensions из scala
  • при определении своих монад
    • .flatMap
    • .pure
    • .tailRecM – оптимизация для вложенных .flatMap вызовов. метод можно делать @tailrec

Id

  • Identity Monad
  • позволяет использовать в коде, где ожидаются монады немонадные значения
  • мощный инструмент для тестов кода построенного на монадах
  • например
    • 123 : Id[Int]
    • "abc" : Id[String]

Either

  • обычный тип из scala
  • операции:
    • .orElse(Either)
    • .ensure(e)(predicate)
    • .recover(partialFunction)
    • .recoverWith(partialFunction)
    • .leftMap(f)
    • .bimap(f, g)
    • .swap
  • syntax:
    • right bias (flatMap/map/filter работающие на правой части Either, есть из коробки в scala 2.12+)
    • a.asRight
    • a.asLeft

MonadError

  • абстракция поверх Either для работы с ошибками
  • параметризирован типом монады и типом ошибки
  • операции
    • .raiseError(e)
    • .handleError(a)(f)
    • .ensure(a)(e)(predicate)
  • syntax
    • .ensure(e)(predicate)

Eval

  • абстракция над выполнением
  • в частности: позволяет делать стекобезопасные рекурсивные вычисления
  • операции
    • .now(f)
    • .later(f)
    • .always(f)
    • .memoize
    • .defer(=> Eval)

Writer

  • сбор лога при вычислении
  • операции
    • val (log, result) = writer.run
    • .mapWritten(f)
    • .bimap(f, g)
    • .mapBoth( (log, res) => ...)
    • .reset
    • .swap
  • syntax:
    • a.pure[T] (требует Monoid[T] в implicit scope)
    • a.tell
    • a.writer(seq)

Reader

  • построение цепочки операций на основе входных параметров
  • ex: DI, encoders
  • операции:
    • .flatMap – позволяет объединить несколько reader от одного входного значения
    • .map

State

  • передача дополнительного состояния в вычисления
  • моделирование мутабельного состояния в pure functional подходе
  • State[S, A] это S => (S, A)
  • операции
    • val (state, res) = a.run(v).value
    • a.runS(v).value
    • a.runA(v).value
  • стандартные преобразования
    • State.get
    • State.set
    • State.pure
    • State.inspect
    • State.modify
  • синтаксис
    • for comprehension

Monad transformers

  • позволяют комбинировать монады
  • комбинация невозможна без знаний об одной из двух монад
  • например, EitherT позволяет комбинировать любую монаду с Either
  • из коробки: cats.data.{OptionT, EitherT, ReaderT, WriterT, StateT, IdT}
  • соглашение: трансформер определяет внутреннюю монаду, а первый его тип - внешнюю. например, OptionT[List, A] – создаст монаду для List[Option[A]]
  • syntax:
    • если нужно часто определять alias для типов в стеках монад, поможет scala compiler plugin king projector. с ним можно писать так: 123.pure[EitherT[Option, String, ?]]
    • .pure
    • .value
  • использование для реализации:
    • многие монады реализованы через трансформеры
    • type ReaderT[F[_], A, B] = Kleisli[F, A, B]
    • type Writer[W, A] = WriterT[Id, W, A]

Kleisli

  • объединение функций A => F[B], B => F[C] в A => F[C]

Semigroupal

  • объединяет два контекста
  • в литературе иногда называют Monoidal
  • операции:
    • .map2 ... .map22
    • .tuple2 ... .tuple22
    • .contramap2 ... .contramap22
    • .imap2 ... .imap22
  • syntax
    • (a, b, c, ...).tupled
    • (a, b, c ...).mapN
    • (Monoid[A], Monoid[B], ...).imapN(toF)(fromF)
  • Intellij Idea не понимает тип выражения после mapN, это недавно поправили
  • Иногда получаемый результат не сразу очевиден. Например Semigroupal от двух списков будет прямое произведение (каждый с каждым), а не zip списков.

Validated

  • аналог Either, но с накоплением всех ошибок
  • требует Semigroup для типа ошибки
  • операции
    • Validated.valid[E, A](a)
    • Validated.invalid[E, A](e)
    • Validated.catchOnly[Throwable](f)
    • Validated.catchNonFatal(f)
    • Validated.fromTry(a)
    • Validated.fromEither[E, A](a)
    • Validated.fromOption[E, A](a, e)
    • .map(f)
    • .leftMap(f)
    • .bimap(f, g)
    • .toEither
    • .withEither(f)
    • .withValidated(f)
    • .getOrElse(a)
    • .fold(f, g)
  • syntax
    • a.valid[E]
    • a.invalid[A]
    • .pure[Validated[F[E], A]]
    • .raiseError[Validated[F[E], A], E]
    • .tupled

Apply

  • Semigroupal + Functor
  • альтернативный к Semigroupal способ закодировать объединение контекстов
  • операции
    • .ap(f)(a)
    • .product(a, b)

Applicative

  • Apply + pure, который позволяет создать новый Applicative instance из сырого значения
  • Monad = Applicative + FlatMap
  • операции
    • .pure(a)

NonEmpty*

  • аналоги стандартных коллекций, но имеющие строго один или более элементов
  • NonEmptyList
  • NonEmptyVector

Foldable

  • абстракция для foldLeft / foldRight
  • операции
    • .foldLeft(a, i)(f)
    • .foldRight(a, i: Eval[B])(f): Eval[B] (stack safe)
    • привычные методы коллекций, поверх foldLeft: .find, .exists, .forall, .toList, .isEmpty, .nonEmpty ...
    • .combineAll(a) (aka .fold, требует Monoid)
    • .foldMap(a)(f) (требует Monoid)
    • .compose(other)
  • syntax:
    • все операции доступны как синтаксис
    • a.foldLeft(i)(f) и т. д.

Traverse

  • имея набор из F[A], получить F от набора А
  • например, List[Future[A]]Future[List[A]]
  • операции
    • .traverse(a)(f)
    • .sequence(a)
  • syntax:
    • a.traverse(f)
    • a.sequence

Обзоры видео на технические темы, январь-сентябрь 2016

Каждый рабочий день, в обеденный перерыв, у меня есть 15-20 минут на просмотр видео. Читать в этот момент не удобно, это отвлекает от процедуры поглощения пищи, а видео в самый раз.

Впечатления от видео за январь-октябрь этого года в этом посте. В последующем планирую переодически делать такие обзоры.

Предыдущий похожий обзор – Видео со ScalaDays 2015 San Francisco.

Scala Monads: Declutter Your Code With Monadic Design – Dan Rosen

  • общие слова про монады, flatmap и map
  • примеры на scalaz
  • Хороший вывод в конце - монады что-то прячут, заменяя это на типы. Option прячет boilerplate от "if non-null" logic, Validation – try/catch и т.д.

The Multi-threading, Non Blocking IO – Heinz Kabutz

Live coding сессия. Объясняется способ написать сервер: блокирующий, неблокирующий на nio, с тредами или с селекторами. Интересно.

Scalaz: the history, the motivation, the battles, the future – Tony Morris

Не интересно.

Фреймворк Akka и его использование в Яндексе – Вадим Цесько

  • Интересно не сколько про саму akka, там уже некоторые вещи неактуальны для новых версий. Для себя вынес только факт того, что не стоит крутить акторы в системном дефолтном диспечере.
  • Интересно было послушать про систему в общем и узнать, как построена структура обработки данных.
  • Интересно смотреть, как это всё меняется, и меняется ли в связи с akka streams.

CRDTs Illustrated – Arnout Engelen

Хороший начальный обзор CRDT с наглядными схемами.

Propositions as Types – Philip Wadler

  • Известный доклад Вадлера. Стоит посмотреть и посмотреть до конца.
  • Вадлер рассказывает об истории развития теоретической базы под разными концепциями, на которых построены языки программирования.
  • Выжимка: все изобретено дважды. Сначала математиками, потом в computer science.

Learning scalaz – Eugene Yokota

  • Очень поверхностный рассказ про scalaz, скорее про проблемы, которые он может решить.
  • В конце – список полезных книг и их обзор.

Zipkin at Twitter – Jeff Smick

Zipkin – система трассировки логов в распределённых сервисах.

  • Подход интересный, в других системах я такого не видел.
  • Сложилось впечатление, что использовать за пределами твиттер-стека не удобно.

Scaling Intelligence: moving ideas forward – Jessica Kerr

Про кривую изучения scala и community вокруг языка. Про то, как должна выглядеть документация и руководства, чтобы они были понятны людям с разными уровнями понимания computer science и математики, присутствующей в scala.

Позиция автора очень релевантна моему представлению о процессе обучения.

Optimising Scala for fun and profit – Rory Graves

Несколько простых и понятных способов понять, что сделать, чтобы scala работала быстрее. Также про магию, которая лежит за красивыми концепциями в scala, и чего это стоит для производительности.


Видео со ScalaDays 2015 San Francisco

Заметки к некоторым видео с главной scala конференции. Все видео и слайды давно доступны на сайте parleys.com.

Scala - where it came from, where it's going - Martin Odersky

Key note конференции. Советую всем, кто интересуется будущим scala и взглядом на это Мартина. Упоминали новый компилятор dotty, scala.js, scala 2.12. Кстати да, DSL для XML собираются вынести из языка в строковые интерполяторы.

Akka HTTP: the Reactive Web Toolkit - Roland Kuhn

Про стримы в Akka, с демонстрациями кода. Роланд начинает с соединения TCP со стримами, описывает реализации кастомных протоколов и доходит к тому, как на всём этом реализован HTTP. В ответах на вопросы к докладу упомянуто много планов по развитию стримов и HTTP в akka. Из важного я узнал, что netty внутри play планируют заменить на новый HTTP core.

Reactive Slick for Database Programming - Stefan Zeiger

В начале доклада капитанские вещи о том, какие проблемы есть с БД в асинхронных окружениях и как их принято решать. Затем описывается state и IO монады. Затем объяснятся как slick решает вопросы доступа к БД, представления результатов и зачем там Futures. Интересную мысль, которую я вынес, что при текущей моделе БД асинхронные драйвера, которые стали появляться, не решают проблему, так как внизу БД всё равно работает в синхронном стиле.

Type-level Programming in Scala 101 - Joe Barnes

Весёлая вводная в type-level программирование без углубления в незначительные на первых этапах детали. С примерами кода и тестов. Доклад в режиме ответов на вопросы, которые, к сожалению, не всегда слышно.

Function-Passing Style, A New Model for Asynchronous and Distributed Programming - Heather Miller

Интересный доклад о попытках написать решение, которое в некоторых случаях может использоваться как замена модели акторов. В двух словах идея в том, что стейт может жить в одном месте, а обработка его вызываться из другого, для чего по сети можно передавать лямбды, вместо данных. При этом топология решения может быть любая, как ptp, так и master-slave, например. Если я всё правильно уловил, уже есть работающий прототип.


Мониторинг CO2 и работа с USB на scala

Озадачился мониторингом CO2 в помещениях. Сначала смотрел на отдельные датчики, думая собрать на коленке и rPi, но потом нашёл дешёвый сборный комплект Masterkit MT8057. Он настолько отличный, что с удовольствием его рекламирую.

В результате у меня получился драйвер к MT8057 на scala и stand alone утилита, ниже в посте поделюсь некоторыми заметками к этой реализации.

Драйвер MT8057

Для MT8057 есть opensource реализация утилиты для съёма параметров от Олега Булатова написанная на C – co2mon. co2mon вариант хороший и рабочий, поддерживает и OS X, и Linux. Наверное, я бы справился докрутить туда выгрузку данных в InfluxDB, куда я собирался сложить все метрики, но решил пописать своих велосипедов, попрактиковаться в низкоуровневых штуках на scala и вспомнить работу с USB.

В первый подход взял хороший и зрелый проект usb4java, но оказалось, что с поддержкой OS X там беда. Требуются извращения типа выгрузки-загрузки kext'ов, которые у меня ещё и не завелись с первого раза.

Во второй подход взял hid4java, этот продукт хоть и анонсируется, как годный к production использованию, ещё достаточно сырой. Шаг влево, шаг вправо и ловишь jvm crash где-то в кишках интеграции с C-шной библиотекой. Написан через JNA, внутри лежат скомпилированные библиотеки для Linux x86_64, Linux ARM, OS X и ещё нескольких платформ. На OS X работает без всяких танцев с kext'ами. Из проблем – API не очень удобный, хуки вызываются из каких попало тредов, у меня это обходится с помощью обёртки с потокобезопасной очередью. Часть методов работает как бы правильно, возвращает правильные Java объекты, но при попытке что-то вызвать у этого объекта получаешь ошибку или crash, так что пришлось добавить костыль.

HID это отдельный класс USB устройств, поэтому не всегда будет выбор между этими библиотеками, в частности usb4java (а вернее libusb) ничего про HID не знает и знать не собирается.

Scala для работы с байтами

В scala всё просто и удобно. Массивы java типа byte[] в Scala превращаются в Array[Byte]. Вооружившись в добавок scala.collection.JavaConversions можно писать привычный scala код.

Внутри драйвера есть зубодробительный код с распаковкой данных от MT8057 и всё это неплохо легло в scala код, местами даже функциональный.

Результат

На выходе у меня получился драйвер MT8057 и декодер к HID пакетам с данными. В отдельный артефакт я их не выделял, но при необходимости это можно сделать.

Про драйвер можно ничего не знать и использовать готовую утилиту ambient7-mt8057-agent которая из зависимостей требует только jre 1.6+ и пока умеет выводить данные в stdout/stderr (для записи в текстовый лог) или работать в интерактивном режиме с ANSI цветами в консоле. На подходе ещё возможность писать в InfluxDB. Готовый jar можно скачать в github.

Про InfluxDB, если удастся с ним подружиться, расскажу отдельно.


Шаблонизация с handlebars и json4s на scala

Занимаюсь неспешно своим проектом scala.moscow. Одна из задач – примитивный генератор статических сайтов. Очень хотелось чего-то простого для шаблонизации. Думал взять mustache, но оказалось, что это уже не совсем модно-молодёжно, так как есть его расширения handlebars и hogan.

Handlebars мне больше приглянулся. Для scala есть нативная реализация на парсер комбинаторах handlebars.scala и её форк. По фичам scala реализация очень ограничена, в частности, нет встроенной поддержки наследования шаблонов, которая в handlebars делается не силами шаблонизатора, а силами helper'ов. В итоге взял handlebars.java, который выглядит достаточно зрелым и имеет в составе, как минимум, helper'ы partial и block для наследования и i18n.

После выбора шаблонизатора встал вопрос как в него загружать данные. Встроенные резолверы не удобно использовать в scala, да и хотелось чего-то более простого, чем создания пачки классов-контейнеров для данных. А что есть проще для описания примитивных структур данных, чем JSON. Для scala нашёлся отличный DSL для JSON - json4s, у которого в частности есть такой лаконичный DSL:

import org.json4s.JsonDSL._

val data =
    ("copyright" ->
      ("year" -> "2015")
    ) ~
    ("assets" -> ("path" -> "/assets")) ~
    ("title" -> "scala.moscow") ~
      ("main" ->
        ("id" -> "main")
      ) ~
      ("about" ->
        ("id" -> "about") ~
        ("title" -> "scala.moscow :: о проекте")
      )
    )

Плюс к этому handlebars и задумывался для комбинации с JSON, что отражается в его синтаксисе. Плюс к этому сразу решается вопрос, где хранить статические данные, которые не нужно генерить программно – в JSON файлах. В json4s конечно есть не только DSL, но и парсеры на основе нативной scala реализации и jackson.

Чтобы подружить handlebars.java и json4s DSL, написал ValueResolver, идею и часть реализации подсмотрел у handlebars-json4s, но доработал её, решил часть проблем и дописал тестов. Как решу оставшиеся проблемы планирую сделать отдельный артефакт.


Akka. Тестирование в общем и про тестирование кластера в частности

Продолжая заниматься hello world'ом на akka погрузился в вопрос тестирования акторов.

Общие вещи просты, не вижу смысла пересказывать документацию, остановлюсь только на ключевых моментах и выводах.

Асинхронное vs синхронное тестирование

Есть два подхода синхронное и асинхронное тестирование. Первое в реальной жизни почти никогда не нужно, если только не хочется протестировать какие-то уж совсем внутренние кишки актора. В остальных случаях, лучше тестировать честно, отправляя и принимая ответы от акторов.

TestProbe и TestActor

Часть которую важно понимать. Сначала я думал, что при тестировании будет какая-то чёрная магия, которая позволит мне получать сообщения, летающие между разными акторами.

На деле всё проще. Внутри вашего TestCase создаётся TestProbe и TestActor, которые затем используются для запросов к акторам и анализа приходящих результатов. К сожалению, в документации сразу показывается пример с trait ImplicitSender, который слегка "гримирует" наличие testActor, что вызвало по началу повышенное количество wtf-per-line.

Соответственно набор стандартных assert'ов на самом деле вызывается у стандартного TestProbe. Конечно же таких TestProbe можно даже создать несколько и, например, поместить в них дополнительные специфичные вам assert'ы.

Отсюда же вывод, что для тестирования parent-child взаимодействия придётся вставлять между ними тестовый актор с проксированием сообщений, в документации описаны способы сделать это. В любом случае production код нужно немного к такому подготовить, другой вопрос, что изменения полезны и для других целей.

Cluster testing

С тестированием кластерных конфигурацию всё не так тривиально.

Для начала есть решение multi-jvm тестирования с плагином для sbt, в документации к akka описано как это всё подружить с тестами, чтобы получить Multi Node Testing. Пригодится и для других задач, когда используется просто akka remote.

Печалит, что нужно серьёзно "испортить" конфиг sbt, но, наверное, можно решить выносом таких тестов в отдельный sbt проект. Также ваша IntelliJ IDEA по понятным причинам про такие тесты ничего знать не будет, так как всё магия работает только в связке с sbt. Думаю, в ScalaIDE будет аналогично.

Простого способа дебажить это тоже нет. Логи не очень удобны, так как валяться в параллель со всех JVM. В идеале нужно писать обёртки, которые будут собирать их по каждой ноде отдельно.

"... напоминает мне игру: "Что? Где? Когда?" называется! Непонятно, что где валяется и когда все это кончится!"

Общерекомендуемый подход писать multi-jvm тесты в одном классе, который будет одинаково выполняться на всех нодах. Это обязывает постоянно следить за тем какой код и где исполняется. Например, написанный в лоб assert будет выполнен на всех нодах, часть из которых может быть ещё не присоединена к кластеру.

Постоянно об это спотыкался, но потом написал себе пару удобных утилиток:

import scala.collection.mutable
import org.scalatest.{ BeforeAndAfterAll, Matchers, Suite }
import akka.cluster.Cluster
import akka.cluster.ClusterEvent.{ CurrentClusterState, MemberUp }
import akka.remote.testconductor.RoleName
import akka.remote.testkit.{ MultiNodeSpec, MultiNodeConfig, MultiNodeSpecCallbacks }
import akka.testkit.ImplicitSender



abstract class MultiNodeBaseSpec(config: MultiNodeConfig)
  extends MultiNodeSpec(config)
  with Suite
  with BeforeAndAfterAll
  with MultiNodeSpecCallbacks
  with ImplicitSender
  with Matchers
{

  override def beforeAll() = {
    super.beforeAll()
    multiNodeSpecBeforeAll()
  }

  override def afterAll() = {
    enterBarrier("before-clean-up")
    cleanUp()
    enterBarrier("clean-up")
    multiNodeSpecAfterAll()
    super.afterAll()
  }

  def cluster: Cluster = Cluster(system)
  cluster.subscribe(testActor, classOf[MemberUp])
  expectMsgClass(classOf[CurrentClusterState])
  println(s"myself address: ${node(myself).address}, role: ${myself.name}")

  val currentClusterNodes = mutable.Set[RoleName]()

  def joinToCluster(nodes: Seq[RoleName], seedNode: RoleName): Unit = {
    currentClusterNodes ++= nodes
    // on new nodes await events for all cluster member
    runOn(nodes: _*) {
      cluster join node(seedNode).address
      (receiveN(currentClusterNodes.size).collect { case MemberUp(member) => member.address }.toSet
        should contain theSameElementsAs currentClusterNodes.map(node(_).address).toSet)
    }

    // on existing nodes await events for only new cluster members
    runOn((currentClusterNodes -- nodes.toSet).toList: _*) {
      (receiveN(nodes.size).collect { case MemberUp(member) => member.address }.toSet
        should contain theSameElementsAs nodes.map(node(_).address).toSet)
    }

    enterBarrier("join-"+ nodes.map(_.name).mkString(","))
  }

  def runOnJoinedNodes(a: => Unit): Unit =
    runOn(currentClusterNodes.toList: _*) {
      a
    }

  def cleanUp(): Unit =
    cluster.unsubscribe(testActor)
}

В базовом spec'е выше реализовано:

  • подписывание на события кластера
  • метод joinToCluster для правильного присоединения к кластеру нод
  • метод runOnJoinedNodes для выполнения кода на уже работающих нодах кластера, аналогичный по использованию встроенному runOn

Тестирование сети

Есть встроенная поддержка тестирования транспорта и сети с возможностью эмуляции проблем между нодами (blackhole). При этом я надеюсь как-нибудь попробовать приспособить docker, его API и iptables для данных целей, благо multi-jvm, кажется умеет сам в тестах упаковывать тестовую ноду в jar, раскладывать через ssh+rsync, а затем запускать.

Примеры

Можно глянуть, что получилось у меня. Много полезных примеров я обнаружил в самих исходниках akka и в проекте akka crdt.

Вывод

Тестировать akka, даже в сложных конфигурациях можно и нужно, но tooling ещё требует доработки.


FPConf 2015 - заметки на полях

article featured image

Побывал на конференции FPConf. Поделюсь своими мыслями, возникшими при прослушивании докладов. Я в основном сидел на втором потоке, где было про scala, UI и пр. Первый поток был преимущественно про Erlang и Haskell.

Организаторы обещали, что будет видео, надеюсь пополнить эту статью ссылкам в будущем.

Upd 09.12.2015: дополнил.

Cамурайский путь молодого scala-программиста, Сергей Лобин, Sputnik.ru

В докладе было мало про scala, больше про проблемы при разработки геокодера в Спутнике. Главный печальный для всех фанатов Scala вывод – Scala в production и них не прижилась, найти разработчиков сложно, Go разработчиков найти значительно проще.

Макросы scala, Михаил Муцянко, JetBrains

Хороший вводный доклад про макросы Scala от разработчика Scala plugin в IDEA.

Из запомнившегося:

Удобный способ построения AST в макросе через Q интерполятор (квазикватирование).

Килер фича, когда Михаил нажатием одной волшебной кнопки прямо в IDEA, показал как разворачивается макрос в Scala код. К сожалению оказалось, что это не из production версии плагина и вроде ожидать такое в ближайшее время не стоит, так как работает не всегда корректно. Очень вкусная возможность, будем ждать.

В 2.12 ожидается значительное улучшение в деле разработки макросов за счёт нового проекта ScalaMeta.

Хорошая ссылка на изучение: What Are Macros Good For? от Евгения Бурмако YouTube, слайды. BTW про самого Евгения и его работу над Scala макросами можно узнать в EaxCast S02E10.

Доклад рекомендую к просмотру.

Встраивание языка в строковой интерполятор, Михаил Лиманский, ЭСК

Хороший практический доклад, как вместо DSL порой можно обойтись интерполятором. Какие возможности, плюсы и минусы такого подхода. Можно прямо брать доклад и писать свой интерполятор как по tutorial'у.

В качестве домашнего задания для себя запомнил задачу реализовать интерполятор для типобезопасного форматирования строки. Хотим с aveic попробовать независимо друг от друга реализовать это и посмотреть, что получиться.

Рекомендую для тех, кто интересуется темой.

Lenses And Prisms, Эдвард Кметт

Самый звёздный докладчик на конференции. К сожалению без знания хотя бы основ синтаксиса Haskell понять что-то было сложно. Докладчик проводил доклад в потрясающей форме - выдавая как из пулемёта кучу кода на Haskell прями в vim'е.

Чтобы понять что к чему, я смотрел на порт этой библиотеки на Scala - Monocle.

В общих словах – это удобный способ изменения иммутабельных структур с возможностью написания максимально абстрактных маленьких кусочков с дальнейшим комбинированием в более сложные кусочки.

Видео к сожалению не выложили.

Реактивные потоки в backend-е, Алексей Романчук, 2ГИС

Хорошая success story про использование akka streams в production. Для меня теперь это один из ответов на вопрос «где нам нужна akka?».

Забавные слайды с цветными "сосиками".

Прозвучавшее число потерь на akka streams по сравнению с голыми акторами ~10%.

Рекомендую всем, кому интересны akka streams.

Scala performance для сомневающихся, Роман Гребенников, Sociohub.ru

Самый запомнившийся доклад. Покрывает сразу две темы - пару примеров того как все модные молодёжные FP штуки из scala отражаются в bytecode JVM и машинном коде, какие потери они за собой несут или не несут. А также способы самому развернуть, померить и понять как выполняется тот или иной код.

Вкратце про проблемы – простой pattern matching по типу параметра - также быстро как колбаса из if'ов. Есть проблемы с boxing/unboxing в Scala collection и прикладывать @specialized не поможет.

Рекомендую к просмотру.

В общем

Очень приятное послевкусие от конференции, не ожидал, что про FP будет так целостно. Как сказали организаторы было 180 человек.

Не посмотрел в живую «Фронтэнд без грусти» Никиты Прокопова, о котором наслышан от коллег, которые видели доклад на какой-то другой конференции. А также хочется поглядеть на «Aрхитектура UI на основе функциональных линз» от Ильи Беда.

Буду ждать видео. Дождались.