Quando si scrive IsHCons.Aux[L, TypedMap, L]
stai chiedendo la prova che il HList L
ha la testa e la coda TypedMap
L
, il che significherebbe che si tratta di un HList infinita, che non è possibile, dal momento che alla Scala non consente questo tipo di tipo arbitrariamente ricorsivo (prova a scrivere qualcosa come type Foo = Int :: Foo
, ad esempio, riceverai un errore "riferimento ciclico illegale"). Probabilmente non è nemmeno quello che vuoi.
In generale è improbabile che si usi IsHCons
molto in Shapeless, poiché è quasi sempre meglio indicare solo la struttura che si desidera nel tipo. Ad esempio, i seguenti due definizioni fanno la stessa cosa:
import shapeless._, ops.hlist.IsHCons
def foo[L <: HList](l: L)(implicit ev: IsHCons[L]) = ev.head(l)
E:
def foo[H, T <: HList](l: H :: T) = l.head
Ma il secondo è ovviamente preferibile (è chiaro, non richiede un'istanza supplementare tipo di classe di essere trovato in fase di compilazione, ecc.), ed è quasi sempre possibile scrivere qualunque cosa tu stia cercando di fare in quel modo.
Si noti inoltre che richiedono un'istanza IsHCons
significa che la ricorsione qui non funziona come previsto, non si può chiamare get
su un HNil
, dal momento che il compilatore non può provare che si tratta di un HCons
(perché non è).
Sei sicuro di aver bisogno di una lista? Se si richiede che tutti i membri della hlist siano di tipo TypedMap
, è possibile utilizzare anche lo Sized
di Shapeless (se si desidera che il tipo acquisisca la lunghezza) o anche solo un semplice vecchio List
.
Se davvero, vuole veramente utilizzare un HList
qui, io suggerirei di scrivere una nuova classe Tipo:
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)
E poi:
scala> get(IntegerField("year"), test)
res3: Option[Int] = Some(23)
scala> get(IntegerField("foo"), test)
res4: Option[Int] = None
Questo è un modello abbastanza comune in Senza forma, induttivamente descrivi come eseguire un'operazione su una hlist vuota, quindi su una hlist con una testa anteposta a una coda che sai come eseguire l'operazione, ecc.
Grazie! So che in questo modo sembra stupido. Il mio obiettivo è costruire qualcosa come HMap' senza forma, ma con una funzione 'get()' che accetta un'istanza generica 'Field [T]' invece di un 'IntegerField',' StringField', ... Nel tuo esempio , come si ricorre se l'oggetto che si sta cercando non è il primo? Se provo a scrivere 'else find (key, l.tail)' ottengo 'found: T, richiesto: shapeless. :: [H, T],' --- ecco perché stavo cercando 'IsHCons.Aux' – kenshin
Ah, buona cattura, ho digitato male e ho aggiornato 'findFieldHCons' in modo che funzioni effettivamente. –
Fantastico! Persino la versione non dumbed funziona come un incantesimo. Grazie :) – kenshin