Получить ключ поля как Coproduct

import shapeless._
import syntax.singleton._

val book = ("author" ->> "Benjamin Pierce") ::
  ("title"  ->> "Types and Programming Languages") ::
  ("id"     ->>  "foo") ::
  ("price"  ->>  "bar") ::
  HNil

Я хочу найти ключ поля, который отображается на "foo" (в этом случае "id") и получить его, напечатанный как Coproduct из 4-х одиночных строк.

Как я могу это сделать?

2 ответа

Я бы посоветовал сделать это немного по-другому (и более обобщенно) с помощью класса пользовательских типов:

import shapeless._
import shapeless.labelled.FieldType

trait RecSearch[R <: HList, A] {
  type Keys <: Coproduct

  def find(r: R, a: A): Option[Keys]
}

object RecSearch extends LowPriorityRecSearchInstances {
  implicit def hnilRecSearch[A]: Aux[HNil, A, CNil] =
    new RecSearch[HNil, A] {
      type Keys = CNil

      def find(r: HNil, v: A): Option[CNil] = None
    }

  implicit def cconsRecSearch1[K, V, T <: HList](implicit
    trs: RecSearch[T, V],
    wit: Witness.Aux[K]
  ): Aux[FieldType[K, V] :: T, V, K :+: trs.Keys] =
    new RecSearch[FieldType[K, V] :: T, V] {
      type Keys = K :+: trs.Keys

      def find(r: FieldType[K, V] :: T, a: V): Option[K :+: trs.Keys] =
        if (r.head == a)
          Some(Coproduct[K :+: trs.Keys](wit.value))
        else trs.find(r.tail, a).map(_.extendLeft[K])
    }
}

trait LowPriorityRecSearchInstances {
  type Aux[R <: HList, A, K <: Coproduct] = RecSearch[R, A] { type Keys = K }

  implicit def cconsRecSearch0[A, K, V, T <: HList](implicit
    trs: RecSearch[T, A]
  ): Aux[FieldType[K, V] :: T, A, K :+: trs.Keys] =
    new RecSearch[FieldType[K, V] :: T, A] {
      type Keys = K :+: trs.Keys

      def find(r: FieldType[K, V] :: T, a: A): Option[K :+: trs.Keys] =
        trs.find(r.tail, a).map(_.extendLeft[K])
    }
}

А потом:

def search[R <: HList, A](r: R)(a: A)(implicit rs: RecSearch[R, A]): Option[rs.Keys] =
  rs.find(r, a)

И наконец:

import syntax.singleton._

val book = ("author" ->> "Benjamin Pierce") ::
  ("title"  ->> "Types and Programming Languages") ::
  ("id"     ->>  "foo") ::
  ("price"  ->>  "bar") ::
  HNil

search(book)("foo")

Который покажет вам (очень подробный) тип копродукта и правильное значение:

Some(Inr(Inr(Inl(id))))

Ваша версия не компилируется для меня, поэтому я не могу сравнить их, но в 95% случаев я начинаю использовать Poly Я заканчиваю тем, что переключился на класс типов в некоторый момент.

Мне нужно сложить HList, создавая Coproduct (или Option[Coproduct]) как я хожу

object folder extends Poly2 {
  implicit def apply[K : Witness.Aux, C <: Coproduct] = at[FieldType[K, Float], Option[C]] { (value, result) =>
    result.fold(
      if (value == "foo") Some(Coproduct[K :+: C](implicitly[Witness.Aux[K]].value)) else None
    )(result => Some(result.extendLeft[K]))
  }
}
book.foldRight(Option.empty[CNil])(folder) // Option
Другие вопросы по тегам