修改无形 HMap 的元素后保留类型
Preserving type after modification of elements of a shapeless HMap
我正在尝试使用 HList
为共享同一父项的对象集合建模。我希望能够:
- 使用索引访问集合中的元素
- 使用在父项上定义的方法转换集合的某些元素
我能够解决上面的第一点(在下面的方法 withIndex
中)。但是,IntelliJ IDEA 显示消息 Expression of type at.Out doesn't conform to expected type T
的突出显示错误。有没有我可以添加的隐式来摆脱这个?
对于第二点(下面的方法modify
),我得到一个编译错误
Error:(31, 13) type mismatch;
found : result.type (with underlying type Value)
required: T
result
我是否可以添加一个隐式来摆脱 asInstanceOf
转换,以便我可以应用 modify
方法?此外,即使在应用 modify
方法后,我也希望能够获得相同类型的对象。如您所见,Additive
和 Multiplicative
正确实现了 modify
方法。我正在努力寻找一种方法来提供证据证明情况确实如此......
这是上面引用的代码:
import shapeless._
import shapeless.ops.hlist.At
sealed trait Value {
val value: Double
def modify(newValue: Double): Value
}
case class Additive(value: Double) extends Value {
def modify(newValue: Double): Additive = this.copy(value = value + newValue)
}
case class Multiplicative(value: Double) extends Value {
def modify(newValue: Double): Multiplicative = this.copy(value = value * newValue)
}
case class Collection[L <: HList](values: L)
(implicit
val ev: LUBConstraint[L, Value]) {
def withIndex[T <: Value](index: Nat)(implicit at: At.Aux[L, index.N, T]): T = values(index)
def modify[T <: Value](index: Nat, newValue: Double)(implicit at: At.Aux[L, index.N, T]): T = {
val value = values(index)
val result = value.asInstanceOf[T].modify(newValue)
result
}
}
object App {
def main(args: Array[String]): Unit = {
val val1 = Additive(1.0)
val val2 = Additive(2.0)
val val3 = Multiplicative(3.0)
val coll = Collection(val1 :: val2 :: val3 :: HNil)
val copyVal1: Additive = coll.withIndex(0)
val copyVal2: Additive = coll.withIndex(1)
val copyVal3: Multiplicative = coll.withIndex(2)
coll.modify(0, 1.0)
coll.modify(1, 2.0)
coll.modify(2, 3.0)
}
}
利用@devkat提供的参考资料,我设法细化了代码,解决了问题中提到的两个问题。在我的实际应用程序中,class 结构更加嵌套,因此我不得不使用 F 有界多态性和自类型来实现所需的结果。为了完整起见,这是我的代码的最终版本。
import shapeless._
import shapeless.ops.hlist.At
sealed trait Value[+V <: Value[V]] {
this: V =>
val value: Double
def modify(newValue: Double): V
def chainModify(newValues: List[Double]): V = {
newValues.foldLeft(this)((obj, v) => obj.modify(v))
}
}
case class Additive(value: Double) extends Value[Additive] {
def modify(newValue: Double) = this.copy(value = value + newValue)
}
case class Multiplicative(value: Double) extends Value[Multiplicative] {
def modify(newValue: Double) = this.copy(value = value * newValue)
}
trait NonCommutative extends Value[NonCommutative] {
}
case class Divisive(value: Double) extends NonCommutative with Value[Divisive] {
def modify(newValue: Double) = this.copy(value = value / newValue)
}
case class Collection[L <: HList](values: L)
(implicit val ev: LUBConstraint[L, Value[_]]) {
def withIndex[T <: Value[T]](index: Nat)(implicit at: At.Aux[L, index.N, T]): T = values(index)
def modify[T <: Value[T]](index: Nat, newValue: Double)(implicit at: At.Aux[L, index.N, T]): T = {
val value = values(index)
val result = value.modify(newValue)
result
}
}
object App {
def main(args: Array[String]): Unit = {
val val1 = Additive(1.0)
val val2 = Additive(2.0)
val val3 = Multiplicative(3.0)
val val4 = Divisive(4.0)
val coll = Collection(val1 :: val2 :: val3 :: val4 :: HNil)
val copyVal1: Additive = coll.withIndex(0)
val copyVal2: Additive = coll.withIndex(1)
val copyVal3: Multiplicative = coll.withIndex(2)
val copyVal4: Divisive = coll.withIndex(3)
println(copyVal3.chainModify(1.0 :: 2.0 :: 3.0 :: Nil))
println(coll.modify(0, 1.0))
println(coll.modify(1, 2.0))
println(coll.modify(2, 3.0))
println(coll.modify(3, 4.0))
}
}
我正在尝试使用 HList
为共享同一父项的对象集合建模。我希望能够:
- 使用索引访问集合中的元素
- 使用在父项上定义的方法转换集合的某些元素
我能够解决上面的第一点(在下面的方法 withIndex
中)。但是,IntelliJ IDEA 显示消息 Expression of type at.Out doesn't conform to expected type T
的突出显示错误。有没有我可以添加的隐式来摆脱这个?
对于第二点(下面的方法modify
),我得到一个编译错误
Error:(31, 13) type mismatch;
found : result.type (with underlying type Value)
required: T
result
我是否可以添加一个隐式来摆脱 asInstanceOf
转换,以便我可以应用 modify
方法?此外,即使在应用 modify
方法后,我也希望能够获得相同类型的对象。如您所见,Additive
和 Multiplicative
正确实现了 modify
方法。我正在努力寻找一种方法来提供证据证明情况确实如此......
这是上面引用的代码:
import shapeless._
import shapeless.ops.hlist.At
sealed trait Value {
val value: Double
def modify(newValue: Double): Value
}
case class Additive(value: Double) extends Value {
def modify(newValue: Double): Additive = this.copy(value = value + newValue)
}
case class Multiplicative(value: Double) extends Value {
def modify(newValue: Double): Multiplicative = this.copy(value = value * newValue)
}
case class Collection[L <: HList](values: L)
(implicit
val ev: LUBConstraint[L, Value]) {
def withIndex[T <: Value](index: Nat)(implicit at: At.Aux[L, index.N, T]): T = values(index)
def modify[T <: Value](index: Nat, newValue: Double)(implicit at: At.Aux[L, index.N, T]): T = {
val value = values(index)
val result = value.asInstanceOf[T].modify(newValue)
result
}
}
object App {
def main(args: Array[String]): Unit = {
val val1 = Additive(1.0)
val val2 = Additive(2.0)
val val3 = Multiplicative(3.0)
val coll = Collection(val1 :: val2 :: val3 :: HNil)
val copyVal1: Additive = coll.withIndex(0)
val copyVal2: Additive = coll.withIndex(1)
val copyVal3: Multiplicative = coll.withIndex(2)
coll.modify(0, 1.0)
coll.modify(1, 2.0)
coll.modify(2, 3.0)
}
}
利用@devkat提供的参考资料,我设法细化了代码,解决了问题中提到的两个问题。在我的实际应用程序中,class 结构更加嵌套,因此我不得不使用 F 有界多态性和自类型来实现所需的结果。为了完整起见,这是我的代码的最终版本。
import shapeless._
import shapeless.ops.hlist.At
sealed trait Value[+V <: Value[V]] {
this: V =>
val value: Double
def modify(newValue: Double): V
def chainModify(newValues: List[Double]): V = {
newValues.foldLeft(this)((obj, v) => obj.modify(v))
}
}
case class Additive(value: Double) extends Value[Additive] {
def modify(newValue: Double) = this.copy(value = value + newValue)
}
case class Multiplicative(value: Double) extends Value[Multiplicative] {
def modify(newValue: Double) = this.copy(value = value * newValue)
}
trait NonCommutative extends Value[NonCommutative] {
}
case class Divisive(value: Double) extends NonCommutative with Value[Divisive] {
def modify(newValue: Double) = this.copy(value = value / newValue)
}
case class Collection[L <: HList](values: L)
(implicit val ev: LUBConstraint[L, Value[_]]) {
def withIndex[T <: Value[T]](index: Nat)(implicit at: At.Aux[L, index.N, T]): T = values(index)
def modify[T <: Value[T]](index: Nat, newValue: Double)(implicit at: At.Aux[L, index.N, T]): T = {
val value = values(index)
val result = value.modify(newValue)
result
}
}
object App {
def main(args: Array[String]): Unit = {
val val1 = Additive(1.0)
val val2 = Additive(2.0)
val val3 = Multiplicative(3.0)
val val4 = Divisive(4.0)
val coll = Collection(val1 :: val2 :: val3 :: val4 :: HNil)
val copyVal1: Additive = coll.withIndex(0)
val copyVal2: Additive = coll.withIndex(1)
val copyVal3: Multiplicative = coll.withIndex(2)
val copyVal4: Divisive = coll.withIndex(3)
println(copyVal3.chainModify(1.0 :: 2.0 :: 3.0 :: Nil))
println(coll.modify(0, 1.0))
println(coll.modify(1, 2.0))
println(coll.modify(2, 3.0))
println(coll.modify(3, 4.0))
}
}