2015-03-29 48 views
5

Bu oldukça aptalca bir örnek çalışmayı yapmaya çalışıyorum, daha sonra onu daha anlamlı bir şeye genişletmeyi planlıyorum. Shapeless: IsHCons, örtük bulamadı

Fakat şimdiye kadar hiçbir şanslar: Ben ben eksik could not find implicit value for parameter ihc

olsun?

sealed trait Field[T] { def name: String } 
case class IntegerField(name: String) extends Field[Int] 
val year = IntegerField("year") 

val test = (year :: 23 :: HNil) :: (year :: 2 :: HNil) :: HNil 

type TypedMap = IntegerField :: Int :: HNil 

def get[L <: HList : <<:[TypedMap]#λ] 
     (key: IntegerField, list: L) 
     (implicit ihc: IsHCons.Aux[L, TypedMap, L] 
    ): Option[Int] = { 

    if(list == HNil) return None 
    val elem: TypedMap = list.head 
    if(elem.head == key) Some(elem.tail.head) 
    else get(key, list.tail) 

} 

get(year, test) 

cevap

11

Eğer hList L Scala buna izin vermez çünkü, mümkün değildir sonsuz hList, var anlamına gelir kafasını TypedMap ve kuyruk L, sahip olduğu kanıt soruyorsun IsHCons.Aux[L, TypedMap, L] yazdığınızda keyfi bir şekilde özyinelemeli tür (örneğin, type Foo = Int :: Foo gibi bir şeyi yazmayı deneyin), "yasadışı döngüsel referans" hatası alırsınız). Muhtemelen istediğin de değil.

Genelde IsHCons'u Shapeless'da kullanma olasılığınız pek fazla değildir, çünkü türünde istediğiniz yapıyı belirtmek neredeyse her zaman iyidir.

import shapeless._, ops.hlist.IsHCons 

def foo[L <: HList](l: L)(implicit ev: IsHCons[L]) = ev.head(l) 

Ve: Örneğin, aşağıdaki iki tanım aynı şeyi yapar

def foo[H, T <: HList](l: H :: T) = l.head 

Ama ikinci (daha anlaşılır olduğunu açıkça tercih edilir olması için ekstra bir tip sınıfı örneği gerektirmez derleme zamanında bulundu, vb.) ve bu şekilde yapmaya çalıştığınız şeyi yazmak neredeyse her zaman mümkündür.

Ayrıca bir IsHCons örneği gerektiren belirtti-Bir HNil üzerinde get çağrı yapamazsınız olarak (Çünkü değil) derleyici bir HCons olduğunu ispat edemez çünkü burada tekrarlama, işe yaramaz anlamına geldiği unutulmamalıdır.

Bir hlisteye ihtiyacınız olduğuna emin misiniz? Eğer hlistenin tüm üyelerinin TypedMap türünü kullanmasını istiyorsanız, Shapeless'in Sized (türün uzunluğu yakalamasını istiyorsanız) veya hatta sadece düz bir eski List'u da kullanabilirsiniz. Sonra

trait FindField[L <: HList] { 
    def find(key: IntegerField, l: L): Option[Int] 
} 

object FindField { 
    implicit val findFieldHNil: FindField[HNil] = new FindField[HNil] { 
    def find(key: IntegerField, l: HNil) = None 
    } 

    implicit def findFieldHCons[H <: TypedMap, T <: HList](implicit 
    fft: FindField[T] 
): FindField[H :: T] = new FindField[H :: T] { 
    def find(key: IntegerField, l: H :: T) = if (l.head.head == key) 
     Some(l.head.tail.head) 
    else fft.find(key, l.tail) 
    } 
} 

def get[L <: HList](key: IntegerField, l: L)(implicit 
    ffl: FindField[L] 
): Option[Int] = ffl.find(key, l) 

Ve:

scala> get(IntegerField("year"), test) 
res3: Option[Int] = Some(23) 

scala> get(IntegerField("foo"), test) 
res4: Option[Int] = None 

Bu oldukça yaygın desen içindedir gerçekten, gerçekten burada bir HList kullanmak istiyorsanız

, ben yeni bir tür sınıf yazma öneririm Shapeless — siz boş bir hlisteki bir operasyonu nasıl yapacağınızı, daha sonra işlemi nasıl yapacağınızı bildiğiniz bir kuyruğa hazır bir kafa ile bir hlistde nasıl indükleyeceğinizi açıklıyorsunuz.

+0

Teşekkürler! Bunun gibi aptalca göründüğünü biliyorum. Amacım, shapeless 'HMap' gibi bir şey inşa etmektir, ancak' 'IntegerField',' StringField' yerine '' Jenerik 'Alan [T]' örneğini kabul eden 'get()' fonksiyonu ile ... Örneğinizde Aradığınız ürün ilk değilse, nasıl tekrarlanırsınız? Eğer bulmaya çalışırsam '' bul (anahtar, l.kutu) '' ı buldum: T, gerekli: shapeless. :: [H, T], '--- bu yüzden isHCons.Aux'unu deniyordum. – kenshin

+0

Ah, iyi yakalama — Yanlış yazdım ve “findFieldHCons” öğesini güncelledim, böylece gerçekten çalışıyor. –

+0

Fantastik! Aptal-aşağı sürümü bile bir çekicilik gibi çalışır. Teşekkür ederim :) – kenshin