Scala Language
Программирование на уровне
Поиск…
Введение в программирование на уровне
Если мы рассмотрим гетерогенный список, в котором элементы списка имеют разные, но известные типы, может быть желательно иметь возможность выполнять операции над элементами списка вместе, не отбрасывая информацию о типе элементов. Следующий пример реализует операцию отображения над простым гетерогенным списком.
Поскольку тип элемента изменяется, класс операций, которые мы можем выполнить, ограничен некоторой формой проекции типа, поэтому мы определяем характеристику Projection
с абстрактным type Apply[A]
вычисляя тип результата проекции, и def apply[A](a: A): Apply[A]
вычисление значения результата проекции.
trait Projection {
type Apply[A] // <: Any
def apply[A](a: A): Apply[A]
}
При реализации type Apply[A]
мы программируем на уровне типа (в отличие от уровня значения).
Наш гетерогенный тип списка определяет операцию map
параметризованную нужной проекцией, а также тип проекции. Результат операции карты является абстрактным, будет варьироваться в зависимости от реализации класса и проекции и, естественно, должен быть HList
:
sealed trait HList {
type Map[P <: Projection] <: HList
def map[P <: Projection](p: P): Map[P]
}
В случае HNil
, пустой гетерогенного списка, результат любой проекции всегда будет сам. Здесь мы объявляем trait HNil
в качестве удобства, чтобы мы могли писать HNil
как тип вместо HNil.type
:
sealed trait HNil extends HList
case object HNil extends HNil {
type Map[P <: Projection] = HNil
def map[P <: Projection](p: P): Map[P] = HNil
}
HCons
- непустой гетерогенный список. Здесь мы утверждаем, что при применении операции с картами результирующий тип заголовка таков, что является результатом применения проекции к начальному значению ( P#Apply[H]
) и что полученный хвостовой тип - это результат преобразования проекция над хвостом ( T#Map[P]
), который, как известно, является HList
:
case class HCons[H, T <: HList](head: H, tail: T) extends HList {
type Map[P <: Projection] = HCons[P#Apply[H], T#Map[P]]
def map[P <: Projection](p: P): Map[P] = HCons(p.apply(head), tail.map(p))
}
Наиболее очевидной такой проекцией является выполнение какой-либо формы операции обертывания - следующий пример дает экземпляр HCons[Option[String], HCons[Option[Int], HNil]]
:
HCons("1", HCons(2, HNil)).map(new Projection {
type Apply[A] = Option[A]
def apply[A](a: A): Apply[A] = Some(a)
})