简体   繁体   English

映射无形HList的类型

[英]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.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)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM