2016-04-29 8 views
3
import shapeless._ 
import syntax.singleton._ 

val book = ("author" ->> "Benjamin Pierce") :: 
    ("title" ->> "Types and Programming Languages") :: 
    ("id"  ->> "foo") :: 
    ("price" ->> "bar") :: 
    HNil 

としてフィールドキーを取得します。私は(この場合は<code>"id"</code>で)<code>"foo"</code>にマップフィールドのキーを検索し、4つのシングルトン文字列の副生成物として入力、ことを検索したい直和

どうすればいいですか?

答えて

0

私はHListを折りたたんで、私が行ったようにCoproduct(またはOption[Coproduct])を構築する必要があります。

object folder extends Poly2 { 
    implicit def apply[K : Witness.Aux, C <: Coproduct] = at[FieldType[K, Float], Option[C]] { (value, result) => 
    result.fold(
     if (value == "foo") Some(Coproduct[K :+: C](implicitly[Witness.Aux[K]].value)) else None 
    )(result => Some(result.extendLeft[K])) 
    } 
} 
book.foldRight(Option.empty[CNil])(folder) // Option 
2

私は、カスタム型クラスで、少し違った(そしてより一般的に)これを行うことをお勧めしたい。そして、

import shapeless._ 
import shapeless.labelled.FieldType 

trait RecSearch[R <: HList, A] { 
    type Keys <: Coproduct 

    def find(r: R, a: A): Option[Keys] 
} 

object RecSearch extends LowPriorityRecSearchInstances { 
    implicit def hnilRecSearch[A]: Aux[HNil, A, CNil] = 
    new RecSearch[HNil, A] { 
     type Keys = CNil 

     def find(r: HNil, v: A): Option[CNil] = None 
    } 

    implicit def cconsRecSearch1[K, V, T <: HList](implicit 
    trs: RecSearch[T, V], 
    wit: Witness.Aux[K] 
): Aux[FieldType[K, V] :: T, V, K :+: trs.Keys] = 
    new RecSearch[FieldType[K, V] :: T, V] { 
     type Keys = K :+: trs.Keys 

     def find(r: FieldType[K, V] :: T, a: V): Option[K :+: trs.Keys] = 
     if (r.head == a) 
      Some(Coproduct[K :+: trs.Keys](wit.value)) 
     else trs.find(r.tail, a).map(_.extendLeft[K]) 
    } 
} 

trait LowPriorityRecSearchInstances { 
    type Aux[R <: HList, A, K <: Coproduct] = RecSearch[R, A] { type Keys = K } 

    implicit def cconsRecSearch0[A, K, V, T <: HList](implicit 
    trs: RecSearch[T, A] 
): Aux[FieldType[K, V] :: T, A, K :+: trs.Keys] = 
    new RecSearch[FieldType[K, V] :: T, A] { 
     type Keys = K :+: trs.Keys 

     def find(r: FieldType[K, V] :: T, a: A): Option[K :+: trs.Keys] = 
     trs.find(r.tail, a).map(_.extendLeft[K]) 
    } 
} 

そして:

def search[R <: HList, A](r: R)(a: A)(implicit rs: RecSearch[R, A]): Option[rs.Keys] = 
    rs.find(r, a) 

そして最後に:

import syntax.singleton._ 

val book = ("author" ->> "Benjamin Pierce") :: 
    ("title" ->> "Types and Programming Languages") :: 
    ("id"  ->> "foo") :: 
    ("price" ->> "bar") :: 
    HNil 

search(book)("foo") 

これはあなたに(非常にv erbose)副生成物の種類と正しい値:

Some(Inr(Inr(Inl(id)))) 

あなたのバージョンは私のためにコンパイルされませんので、私は実際には2つを比較することはできませんが、時間の95%が、私は私が終わるPolyを使用して開始ある時点で型クラスに切り替える。

関連する問題