2017-11-21 16 views
2

2つのHList異種レコードが「同等」であるかどうかをテストすることに興味があります。つまり、同じキー/値のペアを持ちますが、必ずしも同じ順序である必要はありません。下のコード部分でEquivHListsが行うことを行う定義済みの型述語はありますか?2つのscalaの型がないHList型を暗黙的に等価性のためにテストする

// shapeless heterogeneous records with "equivalent" types. 
// these should compile if given as the arguments to 'f' below. 
val hrec1 = ("a" ->> 1) :: ("b" ->> 2) :: HNil 
val hrec2 = ("b" ->> 2) :: ("a" ->> 1) :: HNil 

// only compiles if two HList records contain same information 
def f(hr1: H1 <: HList, hr2 : H2 <: HList)(implicit equiv: EquivHLists[H1, H2]) = { 
    // biz logic 
} 

答えて

4

私はAlign[M,L]タイプキャスがあなたの望むものをサポートしていると考えています。これは、同じタイプの別のものの順序と一致するように1つのhlistの要素を並べ替えることができます。

ここでは、あなたが望むものと思う機能があります。 2つの同等のhlistsがそれぞれのタイプに対して同じ値を持っているかどうかがわかります。 2つのリストの型が同じでなければ、コンパイルされません。

import shapeless._ 
import ops.hlist._ 

def equiv[H <: HList, L <: HList] 
    (h : H, l : L)(implicit align: Align[H, L]): Boolean = align(h) == l 

scala> equiv(3 :: "hello" :: HNil, "hello" :: 3 :: HNil) 
res11: Boolean = true 

scala> equiv(4 :: "hello" :: HNil, "hello" :: 3 :: HNil) 
res12: Boolean = false 

scala> equiv(4 :: "hello" :: HNil, "hello" :: 3.0 :: HNil) 
<console>:19: error: could not find implicit value for parameter align: shapeless.ops.hlist.Align[Int :: String :: shapeless.HNil,String :: Double :: shapeless.HNil] 

編集:hlistsは、同じタイプの複数の値を持っている場合、さらにいくつかの実験の後、これは偽陰性を与えるには:

scala> equiv(3 :: "hello" :: 4 :: HNil, 4 :: "hello" :: 3 :: HNil) 
res14: Boolean = false 

これは、道Align作品は次のとおりです。基本的には1つのhlistを繰り返し処理し、同じタイプの他の要素の最初の要素を取り出します。しかし、シングルトン型リテラルを使用している場合、これは問題ではありません。

だから、これは、少なくともキーに関しては上記のレコードを持つ作業を行います。

scala> equiv(hrec1, hrec2) 
res16: Boolean = true 

//change one of the keys 
scala> val hrec3 = ("c" ->> 2) :: ("a" ->> 1) :: HNil 
hrec3: Int with shapeless.labelled.KeyTag[String("c"),Int] :: Int with shapeless.labelled.KeyTag[String("a"),Int] :: shapeless.HNil = 2 :: 1 :: HNil 

scala> equiv(hrec1, hrec3) 
<console>:27: error: could not find implicit value for parameter align ... 

//change one of the values, it compiles but returns false 
scala> val hrec4 = ("b" ->> 2) :: ("a" ->> 3) :: HNil 
hrec4: Int with shapeless.labelled.KeyTag[String("b"),Int] :: Int with shapeless.labelled.KeyTag[String("a"),Int] :: shapeless.HNil = 2 :: 3 :: HNil 

scala> equiv(hrec1, hrec4) 
res18: Boolean = false 
+0

そこには印象的な機能があります。 –

+0

私は私のためにその仕事をすることができるかもしれません。 'Align'は両方のHListに同じ数のエントリを持たせる必要がありますか?また、 "singleton-aware"になることを望んでいました。それは、私のパイプの夢の上にある 'res12'にあります.4と3は異なるシングルトンタイプを持つので、falseを返すのではなく失敗します。 – eje

+0

同じ数のエントリが必要です。また、私の編集を参照してください、それはシングルトンがキーを認識しています。あなたがシングルトン型のリテラルを作っていれば、値のためにもうまくいくと思います。 –

0
def f(hr1: H1 <: HList, hr2 : H2 <: HList)(implicit equiv: H1 =:= H2) = { 
    // biz logic 
} 

私は、これはあなたが望む何をすべきと考えているあなたはそれを試してみましたか?

+0

'の私の理解=:='それは、正確に等しいのタイプをテストすることであるH1とH2はそうではないかもしれない。無形のために再定義されましたか? – eje

+0

同等のタイプと正確に等しいタイプの間の視点との違いは何ですか?私はそこにあるとは思わない –

+0

上記の例では、 'hrec1'と' hrec2'は、スカラ関係のタプルは異なる順序であり、シングルトン型を使って型付けされているので、異なる型を持っています。 – eje

関連する問題