无形:从副产品到不同副产品的地图

时间:2015-04-27 14:32:35

标签: scala unions shapeless

在下文中,我试图创建一个多态函数将<ul ng-repeat="thing in things"> <li> <p ng-click="$parent.selectedIndex = $index">Name: {{thing.name}}</p> <button class="btn btn-block" ng-show="$parent.selectedIndex == $index">Delete</button> </li> </ul> 转换为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] ^ 应该被视为一个?{/ p>

3 个答案:

答案 0 :(得分:11)

最直接的方法我可以想到将每个元素映射到目标副产品,然后统一结果:

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

这个解决方案并不错,但似乎它可能足以成为一个单独的操作。

答案 1 :(得分:6)

或者,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分开,返回{{} 1}},
  • 映射在结果的左侧,将其转换并打包成Either[String, RefinedFeatureValue]
  • 并将生成的RefinedFeatureValue合并为一个Either[RefinedFeatureValue, RefinedFeatureValue]

答案 2 :(得分:1)

或者,如果您没有设置多态函数,则可以使用此库中的转换类型类:https://github.com/xdotai/typeless/

这是一个转换类型类,它将一个Coproduct转换为另一个Coproduct的选项: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)))