2016-04-29 15 views
8

HListのいくつかの種類のより高い種類に一致する暗黙のdefを使用して再帰的なHList型を構築しています。私は大きくthis postに触発されています。このコードは完璧に働いている暗黙的なdefのスカラー上位の型が "暗黙の値を見つけることができませんでした"と失敗しました

sealed trait HList { 
    type Plus[L <: HList] <: HList 
} 

class HNil extends HList { 
    type Plus[L <: HList] = L 

    def ::[T](v: T) = HCons(v, this) 
} 

case class Appender[L1 <: HList, L2 <: HList, R <: HList](fn: (L1, L2) => R) { 
    def apply(l1: L1, l2: L2) = fn(l1, l2) 
} 

object HNil extends HNil 

object HList { 
    def ++[L1 <: HList, L2 <: HList](l1: L1, l2: L2)(implicit f: Appender[L1, L2, L1#Plus[L2]]): L1#Plus[L2] = f(l1, l2) 

    implicit def nilAppender[L <: HList]: Appender[HNil, L, L] = Appender((v: HNil, l: L) => l) 

    implicit def consAppender[T, L1 <: HList, L2 <: HList, R <: HList](implicit f: Appender[L1, L2, R]): Appender[HCons[T, L1], L2, HCons[T, R]] = { 
    Appender[HCons[T, L1], L2, HCons[T, R]]((l1: HCons[T, L1], l2: L2) => HCons(l1.head, f(l1.tail, l2))) 
    } 
} 

case class HCons[T, U <: HList](head: T, tail: U) extends HList { 
    type Plus[L <: HList] = HCons[T, U#Plus[L]] 

    def ::[V](v: V) = HCons(v, this) 
} 

import HList._ 

val hlist1 = 2.0 :: "hi" :: HNil 
val hlist2 = 1 :: HNil 

val sum = ++(hlist1, hlist2) 
println("last element : " : + sum.tail.tail.head) // prints last element : 1" 

を、私はなぜ知らないが、私は単に既存のHList.++メソッドを呼び出しますHCons++メソッドを追加しようとした場合、これが動作していません。

case class HCons[T, U <: HList](head: T, tail: U) extends HList { 
type Plus[L <: HList] = HCons[T, U#Plus[L]] 

    def ::[V](v: V) = HCons(v, this) 

    def ++[L2 <: HList](l2: L2) = HList.++(this,l2) 
} 

私は、このコンパイルエラーを取得:

could not find implicit value for parameter f: Appender[HCons[T,U],L2,HCons[T,U]#Plus[L2]] 

HConsは、HList。++で定義されているL1タイプのように、HListのサブタイプであるため、OKだと思っていました。

私はこれを試してみたが、それは良く働いていない:

implicit def consAppender[T, L1 <: HList, L2 <: HList, L3, R <: HList](implicit f: Appender[L1, L2, R], ev: L3 <:< HCons[T, L1]): Appender[HCons[T, L1], L2, HCons[T, R]] = { 
    Appender[HCons[T, L1], L2, HCons[T, R]]((l1: L3, l2: L2) => HCons(l1.head, f(l1.tail, l2))) 
    } 

私は何を逃したのですか?

感謝:)あなたはこのことから、あなたの++メソッドの定義を変更する必要があります

+0

私はあなたのやっていることに従わないようにしましたが、3行目の ':HList'は赤い旗です。 'HList'は何のためにも静的型としては無用です。 –

+0

ありがとう、実際には、HListから継承したケースクラスによってオーバーロードされています – Loic

+0

私は混乱を少なくして削除しましたが、動作は同じです – Loic

答えて

10

:これまで

def ++[L2 <: HList](l2: L2) = HList.++(this,l2) 

def ++[L2 <: HList](l2: L2)(implicit f: Appender[HCons[T,U], L2, Plus[L2]]) = HList.++(this,l2) 

コンパイラが右を選択するのに十分な情報を持っていませんメソッド定義内に暗黙の値がありますが、外側からアペンダーを渡す場合、この例は以下のように渡されます:

val hlist1 = 2.0 :: "hi" :: HNil 
val hlist2 = 1 :: HNil 
println(hlist1++hlist2) 

アップデート1:HCons++方法で、我々は暗黙のパラメータが必要ですHList.++メソッドを呼び出します。このパラメータのタイプはAppender[HCons[T, U], L2, HCons[T, U#Plus[L2]]]である必要があります。コンパイラはこの暗黙のパラメータをHList.consAppenderから埋めることができますが、これはタイプAppender[U, L2, U#Plus[L2]]の別の暗黙のパラメータを必要とします。 これは、コンパイラが自身を発見できないパラメータです。です。アップデート2

def ++[L2 <: HList](l2: L2)(implicit f: Appender[U, L2, U#Plus[L2]]): Plus[L2] = HList.++(this, l2) 

コンパイラは(​​で、例えば、検証することができHCons.++メソッド内で我々の場合には、呼び出しサイトで暗黙のパラメータを入力する必要があります。これを知って、上記のコードは、のように簡略化することができます)。これは、2つのアペンダの種類を提供する暗黙の中から選択することができます

Appender[HNil, L, L] 
Appender[HCons[T, L1], L2, HCons[T, R]] 

UHConsある場合にのみ、typeパラメータUは、他の、HNilである場合にのみ、最初のものは使用することができます。しかし、この情報はHCons.++にはありません。それはU <: HListを知っているだけですが、HListの実装がわからないので失敗します。

+0

ありがとう!それは働いている!素敵な:) – Loic

+0

更新1バージョンが動作していない:パラメータfの暗黙の値を見つけることができませんでした:Appender [HCons [T、U]、L2、HCons [T、U] #Plus [L2]] – Loic

+0

それは私のために働きます(Scala 2.11.6を使用)。私たちはもっと深く掘り下げることができますが、最初のバージョンがあなたのために働いている限り、私は満足しています。 – Mifeet

関連する問題