2015-09-25 23 views
1

(注:從Shapeless: Trying to restrict HList elements by their type斯普利特)無形:用自己的餘積約束HList

問題2 - 自己的約束使用上積

我真正想要做的是編寫使用上積了新的約束。

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表] =新CPConstraint [hlLong.type,CPType表] {} //上述線將適合缺少的隱式 - WHY ???

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 
} 
+0

正在處理CPConstraint的隱式解析。具有'val hlLong::: [Long,HNil] = 1L :: HNil'並隱含地查找帶有隱含值的CPConstraint它cpcLong =隱式地[CPConstraint [hlLong.type,CPType]]'我試過'隱式val scpcEmptyLong1 :CPConstraint [:: [Long,HNil],CPType] = new CPConstraint [:: [Long,HNil],CPType] {}',它不適合隱式查找但隱含val scpcEmptyLong2:CPConstraint [hlLong.type, CPType] =新的CPConstraint [hlLong.type,CPType] {}'會。 - 爲什麼?有什麼不同? – sthielo

+0

':: [Long,HNil]'<=>'長:: HNil' – Reactormonk

回答

0

雖然嘗試...我得到它的工作:

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]]  
} 
+0

請將您的解決方案從問題轉移到答案 – dk14

0

這個答案是無恥地從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](或者你可以用實物投影插件的?語法)。