[英]Map the types of a shapeless HList
I've been trying to map the types of an HList
from scala's shapeless
package without having access to their values. 我一直在尝试从scala的
shapeless
包中映射HList
的类型,而无法访问它们的值。
The following succeeds in mapping the values of an 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]
}
}
Cool! 凉! Apart from not being able to use
implicitly[A =:= B]
for some reason, the values of an HList
have been mapped and so have their types. 除了由于某种原因不能
implicitly[A =:= B]
使用implicitly[A =:= B]
,还已经映射了HList
的值,因此也映射了它们的类型。
Now, suppose we don't have the HList
value but we know its type. 现在,假设我们没有
HList
值,但是我们知道它的类型。 How can we map over its types? 我们如何映射其类型?
I tried the following based on the definition of map
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]
}
}
How does one get the type of a mapped HList
without having access to its value? 如何在不访问其值的情况下获取映射的
HList
的类型? Is there a way of debugging why the compiler can't prove something? 有没有一种调试方法,为什么编译器无法证明某些内容? Thankyou for reading.
谢谢您的阅读。
In the case of TestListActualMappedType
you've got the singleton type for mappedList
, which isn't the same as the inferred type of mappedList
. 在
TestListActualMappedType
的情况下,您获得了mappedList
的单例类型,这与推断的mappedList
类型mappedList
。 You can see exactly the same issue without involving Shapeless: 您可以看到完全相同的问题,而无需涉及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]
^
You could ask for evidence that x.type
is a subtype of String
or you could use shapeless.test.typed
, which would look like this in your case: 您可以要求提供证据,证明
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)
This doesn't really buy you much over explicitly specifying the type, though. 不过,这与真正地指定类型相比并没有多大好处。
You can ask for evidence that the output type of a type class like Mapper
is the type you expect for particular input types: 您可以要求提供证据,证明诸如
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>
This is more likely to be useful, but again it depends on what exactly you're trying to convince yourself of. 这更可能有用,但同样取决于您要说服自己的确切方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.