問題
型レベルのプログラミングをサポートするライブラリを使用しているとき、次のようなコメントを書いている自分に気付くことがよくあります ( Strange Loop 2012 で Paul Snivelyによって提示された例から):
// But these invalid sequences don't compile:
// isValid(_3 :: _1 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: _5 :: HNil)
// isValid(_3 :: _4 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: HNil)
/**
* If we wanted to confirm that the list uniquely contains `Foo` or any
* subtype of `Foo`, we could first use `unifySubtypes` to upcast any
* subtypes of `Foo` in the list to `Foo`.
*
* The following would not compile, for example:
*/
//stuff.unifySubtypes[Foo].unique[Foo]
これは、これらのメソッドの動作に関する事実を示すための非常に大雑把な方法であり、これらのアサーションをより正式なものにすることを想像することができます-ユニットまたは回帰テストなどのために.
Shapeless のようなライブラリのコンテキストでこれが役立つ理由の具体例を示すために、数日前に、この質問に対する最初の簡単な回答として、次のように書きました。
import shapeless._
implicit class Uniqueable[L <: HList](l: L) {
def unique[A](implicit ev: FilterAux[L, A, A :: HNil]) = ev(l).head
}
これがコンパイルされることを意図している場合:
('a' :: 'b :: HNil).unique[Char]
これはしませんが:
('a' :: 'b' :: HNil).unique[Char]
unique
この型レベルの forの実装がHList
うまくいかないことに驚いたのFilterAux
は、後者の場合、Shapeless は喜んでインスタンスを見つけるからです。言い換えれば、おそらくコンパイルされないと予想される場合でも、次のコードはコンパイルされます。
implicitly[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]
この場合、私が見たのはバグ、または少なくともバグのようなものであり、その後修正されました.
より一般的には、単体テストのようなものでどのように機能するFilterAux
かについての私の期待に暗示されている種類の不変条件をチェックしたいことを想像できます。型とテストの相対的なメリットに関する最近の議論。
私の質問
問題は、プログラマーが何かをコンパイルしてはならないことを主張できるようにするテスト フレームワーク (プラットフォームを問わない) を私が知らないことです。
この場合に想像できる 1 つのアプローチはFilterAux
、古いImplicit-argument-with-null-default トリックを使用することです。
def assertNoInstanceOf[T](implicit instance: T = null) = assert(instance == null)
これにより、単体テストで次のように記述できます。
assertNoInstanceOf[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]
ただし、次の例は、はるかに便利で表現力豊かです。
assertDoesntCompile(('a' :: 'b' :: HNil).unique[Char])
これ欲しい。私の質問は、このようなものをリモートでサポートするテスト ライブラリまたはフレームワークを誰かが知っているかどうかです。