有一种类型可以通过一组特定的受限类型来参数化:
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}现在,我可以定义一个函数,该函数接受特定类型的集合并对其进行处理:
def consume[T : Base](xs: Seq[T]) =
xs.map(x => implicitly[Base[T]].f(x).mkString("-"))当然是以一种类型安全的方式。
如果我还不是很清楚,下面是我想要的:
consume(Seq(1,"asd", 3)) // => Seq("1-1-1", "a-s-d", "3-3-3")我确信我可以用shapeless的HList实现它,但是核心Scala呢?无论如何,将shapeless标记放在功能倾向的人愿意提供帮助的情况下。
发布于 2015-07-29 07:48:38
import shapeless._
import ops.hlist.Mapper
import ops.hlist.ToList
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
object base extends Poly1 {
implicit def forBase[A : Base] = at[A](x => implicitly[Base[A]].f(x))
}
def consume[T <: HList, Inter <: HList](xs: T)
(implicit
mapBase: Mapper.Aux[base.type, T, Inter],
interToList: ToList[Inter, List[Any]]): Seq[String] = {
xs.map(base).toList.map(_.mkString("-"))
}两个关键部分:
object base extends Poly1:这是一个只在具有Base类型类实例的类型上定义的多态函数。它在它的参数上调用Base.f。consume中的隐式和类型参数: params是我们的输入HList类型。Inter是一个中间类型变量,它是在T.mapBase: Mapper.Aux[base.type, T, Inter]上映射base的结果的输出类型:这证明如果我们在T上映射base,就会得到Inter。我们需要它来调用传入的hlist上的.map。通过将其放入我们的隐式列表中,我们只需要在调用函数时它存在。Shapeless将在可能的情况下为我们生成此代码。如果不能,很可能意味着您忘记了为TinterToList: ToList[Inter, List[Any]]中的类型定义Base实例:这是您可以将HList Inter转换为List[List[Any]]的证据。因此,在Inter中的所有类型中,List[Any]必须是最小的上界类型。同样,通过将它放在输入隐式中,我们只需要shapeless可以为我们生成它。这只是一个样板,用来向编译器证明我们可以调用toList并获得List[List[Any]]。在我的经验sadly.中,我还没有找到一种方法来避免这个和Inter变量
现在,多亏了所有这些隐含,我们只需调用xs.map(base)来获得一个应用了适当Base.f的HList。然后我们调用.toList来获取一个List[List[Any]]。然后我们的Seq[String]就出来了!
下面是它在REPL中的工作原理:
scala> consume(1 :: "asd" :: 3 :: HNil)
res0: Seq[String] = List(1-1-1, a-s-d, 3-3-3)发布于 2014-08-08 01:25:24
这里是消费方法的肮脏的黑客攻击。不是超级类型的安全和好,但作为一个解决办法可能会很好。
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
case class Consumable[T](v: T, base: Base[T])
implicit def toConsumable[T](v: T)(implicit base: Base[T], ev: ClassTag[T]) =
Consumable(v, base)
def consume(xs: Consumable[_]*) =
xs.map(x => x.base.asInstanceOf[Base[Any]].f(x.v).mkString("-"))
println(consume(1, 2, 3))
println(consume("a", "b", "c"))
println(consume(1, 2, "a", "b", "c"))https://stackoverflow.com/questions/25186552
复制相似问题