2014-12-29 12 views
8

Farz edelim ki, argüman uğruna tip kurucu seçeneğine sahip bir Kimliğe sahibim Seçenek [_], yani;Scala, bir KList'in tür parametrelerini HList olarak alıyorum

type Example = Option[Int] :: Option[String] :: HNil 

Tür parametrelerini içeren bir Hlist'i almamın bir yolu var mı?

type Params = Int :: String :: HNil 

Yani, örneğin ben

getOrElse(ex:Example, default:Params):Params 

Şimdi muhtemelen böyle bir formun bir şey arıyorum keyfi getOrElse yöntemi çeşit tanımlamak mümkün (veya yazın yapısı olarak benzer olabilir Ben teklif edilebilir olmayabilir. Muhtemelen mümkündür (

sealed trait GetOrElse[L <: HList] { 
    type Concrete <: HList 
    def getOrElse(ex: L, default: Concrete): Concrete 
} 
object GetOrElse { 
    implicit def nil = new GetOrElse[HNil]{ 
    type Concrete = HNil 
    def getOrElse(ex: HNil, default: HNil) = HNil 
    } 
    implicit def cons[H, T <: HList](implicit tl: GetOrElse[T]) = 
    new GetOrElse[Option[H] :: T]{ 
     type Concrete = H :: tl.Concrete 
     def getOrElse(ex: Option[H] :: T, default: Concrete) = 
     ex.head.getOrElse(default.head) :: 
      tl.getOrElse(ex.tail, default.tail) 
    } 
    def apply[L <: HList](implicit goe: GetOrElse[L]) 
    : GetOrElse[L]{type Concrete = goe.Concrete} = goe 
} 

case class MyOptionList[L <: HList, C](maybes:L)(
    implicit goe: GetOrElse[L]{type Concrete = C}) { 
    def getOrElse(default:C):C = goe.getOrElse(maybes, default) 
} 

:

case class MyOptionList[L <: HList](maybes:L) { 
    type Concrete = {somehow the hlist params types as an Hlist} 
    def getOrElse(default:Concrete):Concrete = ??? 

} 

cevap

6

Ben Miles değilim, ancak mümkün değil güzel elega yapmaya çalıştığınız şeyi başarmak ntly Biçimsizler en Comapped ile: sonra

import shapeless._, ops.hlist.Comapped 

case class MyOptionList[L <: HList, C <: HList](maybes: L)(
    implicit val comapped: Comapped.Aux[L, Option, C] 
) { 
    def getOrElse(default: C): C = default // Not a useful implementation 
} 

Ve:

case class MyOptionList[L <: HList](maybes: L) { 
    def getOrElse[C <: HList: ({ type l[x] = Comapped.Aux[L, Option, x] })#l](
    default: C 
): C = default 
} 

İşte kullanımı: bazı durumlarda yöntemini kısıtlaması koymak için daha uygun olabilir

scala> val x: Int :: HNil = MyOptionList(Option(1) :: HNil).getOrElse(2 :: HNil) 
x: shapeless.::[Int,shapeless.HNil] = 2 :: HNil 

Not aynıdır, ancak vaka sınıfında ekstra tip parametresine sahip değilsiniz. Bu yaklaşımı kullanmak, ancakolmayan üyelere izin vermemek için MyOptionList oluşturulmasını kısıtlamak istiyorsanız, tür parametre listesinde L <: HList: *->*[Option]#λ kullanabilirsiniz.

4

@MilesSabin muhtemelen daha şık bir cevap görünecektir, ancak, elle yinelemeli Şekilsiz iç şeylerin birçoğu yazılı şeklini bu inşa edebilir bir tür parametresi yerine bir tür üye kullanmak için, ancak bu tür bilgileri yediğinde kafam karıştığında, her yerde tür parametrelerini kullanmayı tercih etme eğilimindeyim)

+0

Bir çekicilik gibi çalışır, bu büyük beğeni topluyor. Miles'tan bir şey alıp alamayacağımızı görmek için biraz açık bırakayım ... –

+0

Bu iyi bir doğrudan uygulama. Eğer Travis beni ona dövmemiş olsaydı, seni de 'Comapped' olarak işaret etmiş olurdum. –

İlgili konular