隐式解析在REPL和正常编译中的工作方式不同

时间:2015-08-25 14:00:04

标签: shapeless scala-2.11

我尝试构建一个库,允许使用最少量的样板文件来表示相同数据结构的不同表示。

我的想法是使用shapeless.HList描述所需的表示,将其与实际数据结构匹配,然后使用它来生成所需的表示。

因此,第一步是验证以某种方式描述表示的HList的类型" align"用数据结构的类型来表示。

我不确定无形状是否提供开箱即用的功能,因此我使用TypeAlignement推出了下面的天真shapeless.Generic实现。

import shapeless._

object definition {


  case class Property[A](a: A)
  case class Embed[A](a: A)
  case class Hidden[A](a: A)

  def Prop[X] = Property[X] _
  def Emb[X] = Embed[X] _
  def Hid[X] = Hidden[X] _

  trait Representation[A] {
    type Repr <: HList
    val repr: Repr

  }

  object Representation {
    type Aux[A, R] = Representation[A]{ type Repr = R }
    def apply[A, R <: HList](genA: Generic[A], r: R)(implicit typeAlignment: TypeAlignment[genA.Repr, R]): Aux[A, R] = new Representation[A] {
      type Repr = R
      val repr = r
    }
  }


  case class TypeAlignment[A, B]()

  object TypeAlignment {

    implicit def hnilTypeAlign2: TypeAlignment[HNil, HNil] = new TypeAlignment[HNil, HNil]()

    implicit def propertyRightAlign[A]: TypeAlignment[A, A => Property[A]] = new TypeAlignment[A, A => Property[A]]()
    implicit def embedRightAlign[A]: TypeAlignment[A, A =>  Embed[A]] = new TypeAlignment[A, A => Embed[A]]()
    implicit def hiddenRightAlign[A]: TypeAlignment[A, A =>  Hidden[A]] = new TypeAlignment[A, A => Hidden[A]]()

    implicit def hlistTypeAlign[A, B, TA <: HList, TB <: HList](implicit headAlignment: TypeAlignment[A, B], tailAlignment: TypeAlignment[TA, TB]): TypeAlignment[A :: TA, B :: TB] = new TypeAlignment[A :: TA, B :: TB]()

  }
}

object demo {
  import definition._

  type ACL = String

  case class Address(city: String, street: String, zipcode: String)

  case class User(name: String, age: Option[Int], address: Address, acl : ACL)
  val userRepr = Prop[String] :: Prop[Option[Int]] :: Emb[Address] :: Hid[ACL] :: HNil
  val bogusRepr = Prop[String] :: Prop[Int] :: Emb[Address] :: Hid[ACL] :: HNil


/*
  def makeUserRepr(implicit gen: Generic[User]) = {
    val genUser = Generic[User]
    Representation(genUser, userRepr)
  }
*/

}

当我在scala REPL中尝试时,一切似乎都正常工作:

import shapeless._
import definition._
import demo._
user: demo.User = User(Homer Simpson,Some(42),Address(Springfield,Evergreen terrace,????),admin)
genUser: shapeless.Generic[demo.User]{type Repr = shapeless.::[String,shapeless.::[Option[Int],shapeless.::[demo.Address,shapeless.::[String,shapeless.HNil]]]]} = fresh$macro$5$1@85e91e7

scala> Representation(genUser, bogusRepr)
<console>:18: error: could not find implicit value for parameter typeAlignment: definition.TypeAlignment[genUser.Repr,shapeless.::[String => definition.Property[String],shapeless.::[Int => definition.Property[Int],shapeless.::[demo.Address => definition.Embed[demo.Address],shapeless.::[demo.ACL => definition.Hidden[demo.ACL],shapeless.HNil]]]]]
  Representation(genUser, bogusRepr)
  ^

scala> Representation(genUser, userRepr)
res1: definition.Representation.Aux[demo.User,shapeless.::[String => definition.Property[String],shapeless.::[Option[Int] => definition.Property[Option[Int]],shapeless.::[demo.Address => definition.Embed[demo.Address],shapeless.::[demo.ACL => definition.Hidden[demo.ACL],shapeless.HNil]]]]] = definition$Representation$$anon$1@72bc8c13

当我尝试将UserbogusRepr匹配时,我得到令人满意的编译错误,当我使用正确的Representation时,我得到了userRepr个实例(并作为奖励,我明白发生了什么的好感觉。

当我尝试取消评论makeUserRepr中的demo功能时,问题就开始了。我得到以下编译错误:could not find implicit value for parameter typeAlignment: definition.TypeAlignment[genUser.Repr,shapeless.::[String => definition.Property[String],shapeless.::[Option[Int] => definition.Property[Option[Int]],shapeless.::[demo.Address => definition.Embed[demo.Address],shapeless.::[demo.ACL => definition.Hidden[demo.ACL],shapeless.HNil]]]]]意味着scalac无法在此上下文中推断出TypeAlignment。

我不明白为什么会这样。毕竟,在REPL会话中正确推断出这里隐含的缺失。因此,我推断我并不真正理解发生了什么......

1 个答案:

答案 0 :(得分:0)

好的,我很傻。那些隐含的内容不会从空中出现,所以上面的makeRepresentation方法应该通过隐含参数来获得所需的TypeAlignment,这可能很难表达(因为它取决于Generic[A].Repr

进一步研究无形,我发现了ZipApply hlist操作,它完全符合我的需要。

object definition {


  sealed trait Wrapper[+A]
  case class Property[+A](a: A) extends Wrapper[A]
  case class Embed[+A](a: A) extends Wrapper[A]
  case class Hidden[+A](a: A) extends Wrapper[A]

  def Prop[X] = Property[X] _
  def Emb[X] = Embed[X] _
  def Hid[X] = Hidden[X] _

  trait Representation {
    type Repr <: HList
    val repr: Repr

    def expand[A](a: A)(implicit generic: Generic[A]): generic.Repr = generic.to(a)

    def represent[L <: HList](a: L)(implicit zipApply: ZipApply[Repr, L]) = repr.zipApply(a)

  }


  object Representation {
    type Aux[R] = Representation{ type Repr = R }
    def apply[R <: HList](r: R): Aux[ R] = new Representation {
      type Repr = R
      val repr = r
    }
  }
}

我仍然想在一个函数中合并expandrepresent,但这将是另一个问题。