【问题标题】:Map the types of a shapeless HList映射无形 HList 的类型
【发布时间】:2017-02-10 21:09:33
【问题描述】:

我一直在尝试从 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 值,但我们知道它的类型。我们如何映射它的类型?

我根据maphere的定义尝试了以下:

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 的类型?有没有办法调试为什么编译器不能证明什么?谢谢你的阅读。

【问题讨论】:

    标签: scala types shapeless hlist


    【解决方案1】:

    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>
    

    这更有可能是有用的,但同样取决于您要说服自己的确切内容。

    【讨论】:

    • 谢谢你——这真的很有帮助。在您的第二个代码块中,m 在编译时会发生什么?优化了吗?有什么方法可以在不实际创建任何值的情况下获得 m.Out 的类型?
    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    相关资源
    最近更新 更多