2016-02-21 12 views
6

ich mit hList um geliebäugelt und die folgenden Arbeiten wie erwartet:Erste Elemente aus einem hList

val hl = 1 :: "foo" :: HNil 
val i: Int = hl(_0) 
val s: String = hl(_1) 

Allerdings kann ich nicht das folgende Stück Code bekommen arbeiten (lassen Sie uns für einen Moment mit wahlfreiem Zugriff auf Listen übernehmen ist eine pfiffige Idee ;-)):

class Container(hl: HList) { 
    def get(n: Nat) = hl(n) 
} 

val container = new Container(1 :: "foo" :: HNil) 
val i: Int = container.get(_0) 
val s: String = container.get(_1) 

I get Rückkehr eine Int und String nach ist es Parameter haben möchten. Ich nehme an, wenn überhaupt, ich muss Aux oder at verwenden, aber ich bin nicht sicher, wie man das macht.

Antwort

4

versuchen, etwas in dieser Richtung,

scala> import shapeless._, nat._, ops.hlist._ 
import shapeless._ 
import nat._ 
import ops.hlist._ 

scala> class Container[L <: HList](hl: L) { 
    | def get(n: Nat)(implicit at: At[L, n.N]): at.Out = hl[n.N] 
    | } 
defined class Container 

scala> val container = new Container(1 :: "foo" :: HNil) 
container: Container[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = ... 

scala> container.get(_0) 
res1: Int = 1 

scala> container.get(_1) 
res2: String = foo 

Der erste entscheidende Unterschied hier also eher als hl als einfacher HList eingeben, die über die Arten der Elemente alle spezifischen Informationen verliert, parametrisieren wir über die genaue Art des Arguments und bewahren Sie seine Struktur als L. Der zweite Unterschied besteht darin, dass wir L verwenden, um die implizite Klasseninstanz At zu indexieren, die für die Indizierung in get verwendet wird.

Beachten Sie auch, dass, weil es von Int Literale Nat ist eine implizite Konvertierung ist, können Sie, schreiben

scala> container.get(0) 
res3: Int = 1 

scala> container.get(1) 
res4: String = foo 
+0

Great! Danke für deine Bibliothek! – user3127060