Реализация зависимых от пути типов карт в Shapeless

Я хочу собрать карту, которая содержит отображение зависимого от пути типа от внешнего к внутреннему:

import shapeless._
import shapeless.ops.hlist._

abstract class Outer {
  type Inner
  def inner: Inner
}

private case class Derp(hl: HList) {
  def get(outer: Outer): outer.Inner = hl.select[outer.Inner]
  def put(outer: Outer)(inner: outer.Inner): Derp = Derp(hl :: inner :: HNil)
  def delete(outer: Outer)(c: outer.Inner): Derp = ???
}

Теория заключается в том, что с помощью HList я могу избежать использования селекторов типов и гарантировать, что программы могут получить только в случае Inner который был создан Outer,

Это возможно, или даже хорошая идея? Похоже, что большинство вопросов HList касаются классов arity и case, и я чувствую, что работаю нестандартно.

Обратите внимание, что мне известно о /questions/31713328/karta-s-zavisimyim-ot-puti-tipom-znacheniya/31713339#31713339 но этот вопрос касается, в частности, реализации Shapeless HList - я не знаю, как удалить элементы из HList и потенциально вернуть Option[external. Внутренний].

1 ответ

Решение

Во-первых, вам почти наверняка понадобится параметризовать Derp:

case class Derp[L <: HList](hl: L)

Это потому, что всякий раз, когда у вас есть Derp, компилятор должен будет знать, что его статический HList Тип для того, чтобы сделать что-нибудь полезное.

HList типы кодируют информацию о каждом типе в списке - как

type Foo = Int :: String :: Boolean :: HNil

Как только вы говорите hl: HList, эта информация потеряна.

Далее вы захотите правильно указать типы возврата ваших операций:

def get[O <: Outer](o: O)(implicit selector: Selector.Aux[L, o.type, o.Inner]): o.Inner = selector(hl)

def put[O <: Outer](o: O)(i: o.Inner): Derp[FieldType[o.type, o.Inner] :: L] = copy(hl = field[o.type](i))

Это "пометка" каждого Inner значение с Outerтип, так что вы можете получить его позже (что является Selector.Aux делает). Все интересные вещи в Shapeless происходят через классы типов, которые идут с ним (или которые вы определяете сами), и они полагаются на информацию о типах для работы. Таким образом, чем больше информации о типах вы сможете сохранить в своих операциях, тем проще будет.

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

Бесформенный также имеет HMap, который использует сопоставления ключ-значение как нормальный Map, Разница в том, что каждый тип ключа может отображаться на другой тип значения. Это похоже на ваш вариант использования, но организовано немного по-другому. Использовать HMapВы определяете отношение как функцию типа. Функция типа - это класс типов с зависимым типом:

trait MyRelation[Key] {
  type Value
}

object MyRelation {
  type Aux[K, V] = MyRelation[K] { type Value = V }

  implicit val stringToInt: Aux[String, Int] = new MyRelation[String] { type Value = Int }
  implicit val intToBool: Aux[Int, Boolean] = new MyRelation[Int] { type Value = Boolean }

}

Теперь вы можете определить HMap над MyRelationпоэтому, когда вы используете String ключи вы добавите / получите Int значения, и когда вы используете Int ключи вы добавите / получите Boolean ценности:

val myMap = HMap[MyRelation.Aux]("Ten" -> 10, 50 -> true)
val myMap2 = myMap + ("Fifty" -> 50)
myMap2.get("Ten") // Some(10), statically known as Option[Int]
myMap2.get(44)    // None, statically known as Option[Boolean]

Это немного отличается от вашего примера тем, что у вас есть значение с зависимым типом, и вы хотите использовать внешний тип в качестве ключа, а внутренний тип в качестве значения. Это можно выразить как отношение к HMap а также, используя K#Inner =:= V как отношение. Но это часто удивляет вас тем, что вы не работаете, потому что зависимые от пути типы являются хитрыми и действительно зависят от конкретных подтипов внешнего (который потребует много шаблонов) или синглтон-типов (которые будет трудно обойти без потери необходимых Тип информации).

Другие вопросы по тегам