Shapeless:从联积映射到不同的联积
Shapeless: map from coproduct to different coproduct
在下文中,我试图创建一个多态函数来将 RawFeatureValue
转换为 RefinedFeatureValue
。
import shapeless._
object test {
type RawFeatureValue = Int :+: Double :+: String :+: CNil
type RefinedFeatureValue = Int :+: Double :+: CNil
private object convert extends Poly1 {
implicit def caseInt = at[Int](i => i)
implicit def caseDouble = at[Double](d => d)
implicit def caseString = at[String](s => s.hashCode)
}
val a = Coproduct[RawFeatureValue](12)
val b: RefinedFeatureValue = a map convert
}
但是,生成的类型是 Int :+: Double :+: Int :+: CNil
,它与 RefinedFeatureValue
不兼容。
[error] found : shapeless.:+:[Int,shapeless.:+:[Double,shapeless.:+:[Int,shapeless.CNil]]]
[error] required: test.RefinedFeatureValue
[error] (which expands to) shapeless.:+:[Int,shapeless.:+:[Double,shapeless.CNil]]
[error] val b: RefinedFeatureValue = a map convert
[error] ^
如何告诉 shapeless 两个 Int
应该被视为一个?
我能想到的最直接的方法是将每个元素映射到目标副产品中,然后统一结果:
import shapeless._
type RawFeatureValue = Int :+: Double :+: String :+: CNil
type RefinedFeatureValue = Int :+: Double :+: CNil
object convert extends Poly1 {
implicit val caseInt = at[Int](Coproduct[RefinedFeatureValue](_))
implicit val caseDouble = at[Double](Coproduct[RefinedFeatureValue](_))
implicit val caseString = at[String](s =>
Coproduct[RefinedFeatureValue](s.hashCode))
}
这按预期工作:
scala> val a = Coproduct[RawFeatureValue](12)
a: RawFeatureValue = 12
scala> val b: RefinedFeatureValue = a.map(convert).unify
b: RefinedFeatureValue = 12
scala> val c = Coproduct[RawFeatureValue]("foo")
c: RawFeatureValue = foo
scala> val d: RefinedFeatureValue = c.map(convert).unify
d: RefinedFeatureValue = 101574
这个解决方案还不错,但它看起来确实很有用,足以成为一个单一的操作。
或者,Coproduct
上的方法允许在没有 Poly
的情况下执行此操作(如果您的实际用例允许的话)——并且更少的样板。让我们定义
def refine(v: RawFeatureValue): RefinedFeatureValue =
v.removeElem[String]
.left.map(s => Coproduct[RefinedFeatureValue](s.hashCode))
.merge
那你可以做
scala> val a = Coproduct[RawFeatureValue](12)
a: RawFeatureValue = 12
scala> refine(a)
res1: RefinedFeatureValue = 12
scala> val c = Coproduct[RawFeatureValue]("foo")
c: RawFeatureValue = foo
scala> refine(c)
res2: RefinedFeatureValue = 101574
这包括:
- 一方面将
RawFeatureValue
拆分为 String
,另一方面将其余元素拆分为 RefinedFeatureValue
,并返回 removeElem
Either[String, RefinedFeatureValue]
,
- 结果左边的映射,将其转换并打包成
RefinedFeatureValue
,
- 并将结果
Either[RefinedFeatureValue, RefinedFeatureValue]
合并为一个 RefinedFeatureValue
.
或者,如果您没有设置多态函数,您可以使用此库中的转换类型 class:https://github.com/xdotai/typeless/
这是一个转换类型 class,它将一个副产品转换为另一个副产品的选项:https://github.com/xdotai/typeless/blob/master/src/main/scala/coproduct/convert.scala
添加到依赖项:
libraryDependencies += "ai.x" %% "typeless" % "0.2.5"
代码:
scala> import ai.x.typeless.coproduct.Convert.Ops
import ai.x.typeless.coproduct.Convert.Ops
scala> import shapeless._
import shapeless._
scala> type A = String :+: Double :+: CNil
defined type alias A
scala> type B = Double :+: String :+: List[Int] :+: CNil
defined type alias B
scala> Coproduct[A]("test").convert[B]
res0: Option[B] = Some(Inr(Inl(test)))
在下文中,我试图创建一个多态函数来将 RawFeatureValue
转换为 RefinedFeatureValue
。
import shapeless._
object test {
type RawFeatureValue = Int :+: Double :+: String :+: CNil
type RefinedFeatureValue = Int :+: Double :+: CNil
private object convert extends Poly1 {
implicit def caseInt = at[Int](i => i)
implicit def caseDouble = at[Double](d => d)
implicit def caseString = at[String](s => s.hashCode)
}
val a = Coproduct[RawFeatureValue](12)
val b: RefinedFeatureValue = a map convert
}
但是,生成的类型是 Int :+: Double :+: Int :+: CNil
,它与 RefinedFeatureValue
不兼容。
[error] found : shapeless.:+:[Int,shapeless.:+:[Double,shapeless.:+:[Int,shapeless.CNil]]]
[error] required: test.RefinedFeatureValue
[error] (which expands to) shapeless.:+:[Int,shapeless.:+:[Double,shapeless.CNil]]
[error] val b: RefinedFeatureValue = a map convert
[error] ^
如何告诉 shapeless 两个 Int
应该被视为一个?
我能想到的最直接的方法是将每个元素映射到目标副产品中,然后统一结果:
import shapeless._
type RawFeatureValue = Int :+: Double :+: String :+: CNil
type RefinedFeatureValue = Int :+: Double :+: CNil
object convert extends Poly1 {
implicit val caseInt = at[Int](Coproduct[RefinedFeatureValue](_))
implicit val caseDouble = at[Double](Coproduct[RefinedFeatureValue](_))
implicit val caseString = at[String](s =>
Coproduct[RefinedFeatureValue](s.hashCode))
}
这按预期工作:
scala> val a = Coproduct[RawFeatureValue](12)
a: RawFeatureValue = 12
scala> val b: RefinedFeatureValue = a.map(convert).unify
b: RefinedFeatureValue = 12
scala> val c = Coproduct[RawFeatureValue]("foo")
c: RawFeatureValue = foo
scala> val d: RefinedFeatureValue = c.map(convert).unify
d: RefinedFeatureValue = 101574
这个解决方案还不错,但它看起来确实很有用,足以成为一个单一的操作。
或者,Coproduct
上的方法允许在没有 Poly
的情况下执行此操作(如果您的实际用例允许的话)——并且更少的样板。让我们定义
def refine(v: RawFeatureValue): RefinedFeatureValue =
v.removeElem[String]
.left.map(s => Coproduct[RefinedFeatureValue](s.hashCode))
.merge
那你可以做
scala> val a = Coproduct[RawFeatureValue](12)
a: RawFeatureValue = 12
scala> refine(a)
res1: RefinedFeatureValue = 12
scala> val c = Coproduct[RawFeatureValue]("foo")
c: RawFeatureValue = foo
scala> refine(c)
res2: RefinedFeatureValue = 101574
这包括:
- 一方面将
RawFeatureValue
拆分为String
,另一方面将其余元素拆分为RefinedFeatureValue
,并返回removeElem
Either[String, RefinedFeatureValue]
, - 结果左边的映射,将其转换并打包成
RefinedFeatureValue
, - 并将结果
Either[RefinedFeatureValue, RefinedFeatureValue]
合并为一个RefinedFeatureValue
.
或者,如果您没有设置多态函数,您可以使用此库中的转换类型 class:https://github.com/xdotai/typeless/
这是一个转换类型 class,它将一个副产品转换为另一个副产品的选项:https://github.com/xdotai/typeless/blob/master/src/main/scala/coproduct/convert.scala
添加到依赖项:
libraryDependencies += "ai.x" %% "typeless" % "0.2.5"
代码:
scala> import ai.x.typeless.coproduct.Convert.Ops
import ai.x.typeless.coproduct.Convert.Ops
scala> import shapeless._
import shapeless._
scala> type A = String :+: Double :+: CNil
defined type alias A
scala> type B = Double :+: String :+: List[Int] :+: CNil
defined type alias B
scala> Coproduct[A]("test").convert[B]
res0: Option[B] = Some(Inr(Inl(test)))