【问题标题】:Shapeless: own HList constraint using CoproductShapeless:使用 Coproduct 的自己的 HList 约束
【发布时间】:2017-11-14 23:14:26
【问题描述】:

(注意:从Shapeless: Trying to restrict HList elements by their type 拆分)

问题 2 - 使用 Coproduct 的自身约束

我真正想做的是使用 Coproduct 编写一个新的约束。

trait CPConstraint[L <: HList, CP <: Coproduct] extends Serializable
object CPConstraint {
  import shapeless.ops.coproduct.Selector._

  def apply[L <: HList, CP <: Coproduct](implicit cpc: CPConstraint[L, CP]): CPConstraint[L, CP] = cpc

  type <*<[CP <: Coproduct] = {  // TODO: just invented a symbol ... what would be an appropriate one?
    type λ[L <: HList] = CPConstraint[L, CP]
  }

implicit def hnilCP[HN <: HNil, CP <: Coproduct]: CPConstraint[HN, CP] = new CPConstraint[HN, CP] {}
implicit def hlistCP[H, T <: HList, CP <: Coproduct](implicit ev: coproduct.Selector[CP, H], cpct: CPConstraint[T, CP]): CPConstraint[H :: T, CP] = new CPConstraint[H :: T, CP] {}

}

object testCPConstraint {
  import shapeless.ops.coproduct.Selector._
  import CPConstraint._

  type CPType = Long :+: String :+: CNil

  implicit val selLong = implicitly[Selector[CPType, Long]]
  implicit val selString = implicitly[Selector[CPType, String]]

  def acceptCP[L <: HList : <*<[CPType]#λ](l: L) = true

  val hlLong: ::[Long, HNil] = 1L :: HNil
  val hlString: ::[String, HNil] = "blabla" :: HNil
  val hlMixed: ::[String, ::[Long, HNil]] = "blabla" :: 1L :: HNil
  val hlMixedRev: ::[Long, ::[String, HNil]] = 1L :: "blabla" :: HNil
  val hlInvalid: ::[Double, HNil] = 1.0d :: HNil

  implicit val scpcEmpty: CPConstraint[HNil, CPType] = implicitly[CPConstraint[HNil, CPType]]

  implicit val scpcEmptyLong1: CPConstraint[::[Long,HNil], CPType] = new CPConstraint[::[Long,HNil], CPType] {}

// 隐式 val scpcEmptyLong2: CPConstraint[hlLong.type, CPType] = new CPConstraint[hlLong.type, CPType] {} // 上面的行将适合缺少的隐式 - 为什么???

  implicit val cpcLong = implicitly[CPConstraint[hlLong.type, CPType]]

  val validEmpty = acceptCP(HNil: HNil)
  val validLong = acceptCP(1l :: HNil)
  val validMixed = acceptCP("blabla" :: 1l :: HNil)

  val invalid = acceptCP(1.0d :: HNil) // should fail due to missing evidence
}

【问题讨论】:

  • 处理 CPConstraint 的隐式解析。拥有val hlLong: ::[Long, HNil] = 1L :: HNil 并使用implicit val cpcLong = implicitly[CPConstraint[hlLong.type, CPType]] 为它隐式查找CPConstraint 我尝试了implicit val scpcEmptyLong1: CPConstraint[::[Long,HNil], CPType] = new CPConstraint[::[Long,HNil], CPType] {},它不适合隐式搜索但implicit val scpcEmptyLong2: CPConstraint[hlLong.type, CPType] = new CPConstraint[hlLong.type, CPType] {} 会。 - 为什么???有什么区别?
  • ::[Long,HNil] Long :: HNil

标签: scala constraints shapeless hlist


【解决方案1】:

在试验时......我得到了它的工作:

import shapeless.ops.coproduct
import shapeless.{:+:, ::, CNil, Coproduct, HList, HNil}

/**
 * constraint that checks {{{shapeless.HList}}} elements to be of a type contained in a {{{shapeless.Coproduct}}}
 */
trait CPConstraint[L <: HList, CP <: Coproduct] extends Serializable

object CPConstraint {
  def apply[L <: HList, CP <: Coproduct](implicit cpc: CPConstraint[L, CP]): CPConstraint[L, CP] = cpc

  type <*<[CP <: Coproduct] = {
    type λ[L <: HList] = CPConstraint[L, CP]
  }

  implicit def hnilCP[HN <: HNil, CP <: Coproduct]: CPConstraint[HN, CP] = new CPConstraint[HN, CP] {}
  implicit def hlistCP[H, T <: HList, CP <: Coproduct](implicit ev: coproduct.Selector[CP, H], cpct: CPConstraint[T, CP]): CPConstraint[H :: T, CP] = new CPConstraint[H :: T, CP] {}
}

object testCPConstraint {
  import CPConstraint._

  type CPType = Long :+: String :+: CNil
  def acceptCP[L <: HList : <*<[CPType]#λ](l: L) = true

  val hlLong = 1L :: (HNil: HNil)
  val hlString = "blabla" :: HNil
  val hlMixed = "blabla" :: 1L :: HNil
  val hlMixedRev = 1L :: "blabla" :: HNil
  val hlInvalid = 1.0d :: HNil

  val validEmpty = acceptCP(HNil)
  val validEmpty2 = acceptCP(HList())
  val validEmpty3 = acceptCP(HNil: HNil)
  val validString = acceptCP(hlString)
  val validLong = acceptCP(hlLong)
  val validMixed = acceptCP(hlMixed)
  val validMixedRev = acceptCP(hlMixedRev)
  //  val invalid = acceptCP(hlInvalid) // -> fails due to missing evidence (as expected)

  implicit val scpcEmpty = implicitly[CPConstraint[HNil, CPType]]

  //  implicit val cpcLong = implicitly[CPConstraint[hlLong.type, CPType]]
  // I still don't understand why above line doesn't work, but the following does ???
  implicit val cpcLong2 = implicitly[CPConstraint[::[Long,HNil], CPType]]    
}

【讨论】:

  • 请将您的解决方案从问题移到答案
【解决方案2】:

这个答案是从gitter 中无耻复制的,所有功劳归于@SystemFW。

使用LiftAll 见证,如下所示:

import shapeless._, ops.hlist.LiftAll, ops.coproduct.Inject

type Cop = Int :+: Long :+: CNil

def foo[H <: HList](implicit ev: LiftAll[Inject[Cop,?], H]) = null

foo[Int :: Long :: HNil]
foo[HNil]
foo[Int :: Int :: HNil]
//foo[Int :: Long :: String :: HNil] doesn't compile

其中Inject[Cop,?]type I[X] = Inject[Cop,X](或者您可以使用? 语法的kind 投影仪插件)。

【讨论】:

    猜你喜欢
    • 2023-02-24
    • 2018-10-25
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 2020-07-22
    • 2023-03-31
    相关资源
    最近更新 更多