映射无形 HList 的类型
Map the types of a shapeless HList
我一直在尝试从 scala 的 shapeless
包映射 HList
的类型,但无法访问它们的值。
下面成功映射了一个HList的值
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
值,但我们知道它的类型。我们如何映射它的类型?
我根据 map
here 的定义尝试了以下操作:
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]
}
}
如何在无法访问其值的情况下获取映射 HList
的类型?有没有办法调试为什么编译器不能证明什么?谢谢阅读。
在 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.type
是 String
的子类型,或者您可以使用 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)
不过,这并没有比明确指定类型给你带来多少好处。
您可以要求证据证明类型 class 的输出类型如 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@6f3598cd
scala> implicitly[m.Out =:= (String :: Int :: HNil)]
res1: =:=[m.Out,shapeless.::[String,shapeless.::[Int,shapeless.HNil]]] = <function1>
这更有可能有用,但这同样取决于您要说服自己的确切内容。
我一直在尝试从 scala 的 shapeless
包映射 HList
的类型,但无法访问它们的值。
下面成功映射了一个HList的值
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
值,但我们知道它的类型。我们如何映射它的类型?
我根据 map
here 的定义尝试了以下操作:
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]
}
}
如何在无法访问其值的情况下获取映射 HList
的类型?有没有办法调试为什么编译器不能证明什么?谢谢阅读。
在 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.type
是 String
的子类型,或者您可以使用 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)
不过,这并没有比明确指定类型给你带来多少好处。
您可以要求证据证明类型 class 的输出类型如 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@6f3598cd
scala> implicitly[m.Out =:= (String :: Int :: HNil)]
res1: =:=[m.Out,shapeless.::[String,shapeless.::[Int,shapeless.HNil]]] = <function1>
这更有可能有用,但这同样取决于您要说服自己的确切内容。