scala – 映射无形HList的类型

我一直在尝试从 scala的无形包中映射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]
  }

}

凉!除了由于某种原因无法隐式使用[A =:= B]之外,HList的值已被映射,因此它们的类型也是如此.

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

我根据地图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)

尽管如此,这并没有明确指定类型.

您可以要求提供证据证明类型类的输出类型(如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.HNil]]] = <function1>

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

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...