映射无形HList的类型

时间:2016-10-02 23:44:09

标签: scala types shapeless hlist

我一直在尝试从scala的In [33]: next(zip(*itertools.groupby(L))) Out[33]: (1, 2, 3, 4, 3) 包中映射HList的类型,而无法访问其值。

以下成功映射HList的值

shapeless

酷!除了由于某些原因无法使用import shapeless._ import shapeless.Poly._ import ops.hlist.Mapper import ops.hlist.Mapper._ trait Person { type Value val v : Value } case class StringPerson extends Person { type Value = String val v = "I like strings" } case class IntPerson extends Person { type Value = Int val v = 42 } object what_is_going_on { object test_value_op { val stringPerson = StringPerson() val intPerson = IntPerson() trait lpvfun extends Poly1 { implicit def default[A <: Person] = at[A](_.v) } object vfun extends lpvfun {} // Use these to generate compiler errors if the mapped type is not what we'd expect: type TestListType = StringPerson :: IntPerson :: HNil type TestListExpectedMappedType = String :: Int :: HNil // Input: val testList : TestListType = stringPerson :: intPerson :: HNil // Output: val mappedList : TestListExpectedMappedType = testList map vfun // Get the actual mapped type type TestListActualMappedType = mappedList.type // This compiles...... val mappedList1 : TestListActualMappedType = mappedList // .... but weirdly this line doesn't. That isn't the point of this question, but I'd be very grateful for an answer. //implicitly[TestListActualMappedType =:= TestListExpectedMappedType] } } 之外,implicitly[A =:= B]的值已经映射,因此它们的类型也是如此。

现在,假设我们没有HList值,但我们知道它的类型。我们如何映射其类型?

我根据HList here的定义尝试了以下内容:

map

如何在无法访问其值的情况下获取映射的object test_type_op { type TestListType = StringPerson :: IntPerson :: HNil type TestListExpectedMappedType = String :: Int :: HNil // Attempt 1 does not work, compiler cannot prove =:= type MappedType = Mapper[vfun.type, TestListType]#Out implicitly[MappedType =:= TestListExpectedMappedType] // Attempt 2 does not work, compiler cannot prove =:= class GetMapper { implicit val mapper : Mapper[vfun.type, TestListType] implicitly[mapper.Out =:= TestListExpectedMappedType] } } 的类型?有没有办法调试为什么编译器无法证明什么?谢谢你的阅读。

1 个答案:

答案 0 :(得分:4)

TestListActualMappedType的情况下,您获得了mappedList的单身人士类型,这与mappedList的推断类型不同。如果不涉及Shapeless,您可以看到完全相同的问题:

scala> val x = "foo"
x: String = foo

scala> implicitly[x.type =:= String]
<console>:13: error: Cannot prove that x.type =:= String.
       implicitly[x.type =:= String]
                 ^

您可以要求提供x.typeString的子类型的证据,或者您可以使用shapeless.test.typed,在您的情况下看起来像这样:

import shapeless._, ops.hlist.Mapper

trait Person {
  type Value
  val v : Value
}

case class StringPerson() extends Person {
  type Value = String
  val v = "I like strings"
}

case class IntPerson() extends Person {
  type Value = Int 
  val v = 42
}

trait lpvfun extends Poly1 {
  implicit def default[A <: Person] = at[A](_.v)
} 

object vfun extends lpvfun {}

val stringPerson = StringPerson()
val intPerson = IntPerson()

val testList = stringPerson :: intPerson :: HNil
val mappedList = testList map vfun

shapeless.test.typed[String :: Int :: HNil](mappedList)

但是,对于明确指定类型,这并没有给你带来太大的收获。

您可以要求提供证据证明类型类Mapper的输出类型是您对特定输入类型所期望的类型:

scala> val m = Mapper[vfun.type, StringPerson :: IntPerson :: HNil]
m: shapeless.ops.hlist.Mapper[vfun.type,shapeless.::[StringPerson,shapeless.::[IntPerson,shapeless.HNil]]]{type Out = shapeless.::[String,shapeless.::[Int,shapeless.HNil]]} = shapeless.ops.hlist$Mapper$$anon$5@6f3598cd

scala> implicitly[m.Out =:= (String :: Int :: HNil)]
res1: =:=[m.Out,shapeless.::[String,shapeless.::[Int,shapeless.HNil]]] = <function1>

这更有可能是有用的,但这又取决于你究竟想要说服自己的具体内容。