После сообщения о представлении ADT на четырех разных языках: Scala, Haskell, Rust и TypeScript я задумался о том, как это будет работать в мире Kotlin.

Итак, сначала нам нужно определить наш тип данных. Мы возьмем Tree по двум причинам:

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

Запечатанные классы Kotlin - это распространенный способ реализации ADT.

Сначала давайте посмотрим на реализацию, а затем подробно обсудим, как это работает:

Итак, наш общий интерфейс Tree. Поскольку это общая структура данных, мы определяем ее с помощью параметра типа: Tree<T>. Мы также используем аннотацию out отклонения, чтобы указать, что этот тип ковариантен. Далее мы обсудим, почему.

Поскольку все пустые деревья одинаковы, мы объявляем Empty одноэлементным объектом, расширяющим Tree<Nothing>().

Существует много путаницы между Any, Nothing и <*> (также называемой звездной проекцией). В этом случае звездная проекция просто не сработает. Но вы можете определить Empty как Tree<Any>(), и он будет компилироваться. На следующем шаге мы увидим, почему это ошибка.

Теперь давайте посмотрим на класс Node. Имеет большой смысл определить его как класс данных, поскольку он предоставит нам, по крайней мере, хороший toString() метод.

Обратите внимание, как мы указываем значения по умолчанию для свойств left и right:

val left: Tree<T> = Empty

Здесь в игру вступают как ковариация, так и Nothing.

Независимо от того, к какому типу принадлежит наш T, Nothing находится внизу иерархии классов, поэтому его можно использовать.

Это печатает:

Node(value=42, left=Empty, right=Node(value=62, left=Empty, right=Empty))

Благодаря параметрам по умолчанию нам не нужно было указывать left и right для листового узла, что приятно.

Но печать в целом не так уж и интересна.

Как насчет того, чтобы просуммировать значения всех узлов?

В этом реальная сила ADT в целом и закрытых классов Kotlin в частности.

Поскольку наши классы запечатаны, выражение when является исчерпывающим и кратким.

println(tree.sum()) // 104

Выводы

  • Котлин предоставляет хорошие возможности для реализации ADT
  • Используйте object, если у вашего варианта нет состояния
  • В противном случае отдавайте предпочтение data class
  • when expression - это мощный инструмент для работы с ADT в Kotlin

Больше чтения: