Я пытаюсь добиться следующего - и использование бесформенного выглядит хорошим путем.
Учитывая текущую модель класса:
import shapeless._
object ShapelessTest {
case class Definition[T](id: String) extends Typeable[T] {
type V = Value[T]
override def cast(t: Any): Option[T] = createValue(t.asInstanceOf[Option[T]]).value
override def describe: String = s"$id"
def createValue(value: Option[T]): V =
Value[T](this, value)
}
case class Value[T](definition: Definition[T], value: Option[T])
val DefA: Definition[Int] = Definition[Int]("defA")
val DefB: Definition[String] = Definition[String]("defB")
case class Instance(valA: DefA.V,
valB: DefB.V)
def main(args: Array[String]): Unit = {
val Empty: Instance = Instance(
DefA.createValue(None),
DefB.createValue(None)
)
println(s"Empty manual: $Empty")
val emptyHl = Generic[Instance].from(DefA.createValue(None) :: DefB.createValue(None) :: HNil)
println(s"Empty hlist: $emptyHl")
}
}
Я могу создать пустой экземпляр как Empty
экземпляр, вручную вызывая методы createValue
для правильных определений, или путем преобразования HList с использованием бесформенного.
Я пытаюсь выяснить, возможно ли программно создать экземпляр Empty
для каждого класса, имеющего поля типа Value
.
Другими словами, я хотел бы иметь возможность вызывать
val Empty: Instance = empty[Instance]
и иметь тот же результат, что и emptyHl
или Empty
instance.
Это похоже на пример "8.3 Генератор случайных значений" в бесформенном руководстве, но вместо генерации случайных чисел, используя функции для каждого типа, присутствующего в классе case, я пытаюсь материализовать конкретный тип Definition
для каждого параметра и вызвать для него метод createValue(None)
.
Я безуспешно пытался.
Использование hlist.Mapper
с * 1 028 * определено для Typeable
, я могу получить список параметров, но я не могу вызвать какие-либо методы для набираемого текста.
Любая помощь будет принята с благодарностью, спасибо! :)
Update 9 Apr
Я смог придумать очень запутанное решение - к сожалению, много кастинга, но делает свою работу.
Я бы хотел бы повторить это и сделать это лучше. Я пытался использовать natMapper: NatTRel
, но я не смог заставить его работать с Singleton Types. Я уверен, что это может быть сделано намного лучше, хотя! Любое предложение приветствуется.
import shapeless.ops.hlist
import shapeless.ops.hlist.{Comapped, Reify}
import shapeless.{Generic, HList, HNil}
object ShapelessTest2 {
case class Definition[T](id: String) {
type V = Value[this.type]
def createValue(value: Option[T]) =
new Value[this.type] {
type NT = T
override val valueT: Option[T] = value
override val attrDef: Definition.this.type = Definition.this
}
}
trait Value[D] {
type NT
val attrDef: D
val valueT: Option[NT]
}
object DefA extends Definition[Int]("defA")
object DefB extends Definition[Int]("defB")
object DefC extends Definition[String]("defC")
case class Instance(valA: DefA.V,
valB: DefB.V,
valC: DefC.V)
// Compile safe
val Inst1: Instance = Instance(
DefA.createValue(Some(1)),
DefB.createValue(Some(2)),
DefC.createValue(Some("2"))
)
def main(args: Array[String]): Unit = {
def empty[A <: Product] = new PartiallyApplied[A]
class PartiallyApplied[A <: Product] {
def apply[
V <: HList,
DL <: HList,
RDL <: HList,
H <: Definition[_],
T <: HList
]()(
implicit
gen: Generic.Aux[A, V],
comapped: Comapped.Aux[V, Value, DL],
reify: Reify.Aux[DL, RDL],
isHCons: hlist.IsHCons.Aux[RDL, H, T],
): A = {
def getEmpties[L](list: RDL): V = {
val hlist = list match {
case HNil => HNil
case _ => list.head.createValue(None) :: getEmpties(list.tail.asInstanceOf[RDL])
}
hlist.asInstanceOf[V]
}
val empties = getEmpties(reify.apply())
gen.from(empties)
}
}
val emptyInstance = empty[Instance]()
println(s"Empty valA: ${emptyInstance.valA.attrDef} - ${emptyInstance.valA.valueT}")
println(s"Empty valB: ${emptyInstance.valB.attrDef} - ${emptyInstance.valB.valueT}")
println(s"Empty valC: ${emptyInstance.valC.attrDef} - ${emptyInstance.valC.valueT}")
}
}
Правильно печатает
Empty valA: Definition(defA) - None
Empty valB: Definition(defB) - None
Empty valC: Definition(defC) - None