问题
当我使用支持类型级编程的库时,我经常会写出像下面这样的注释(来自Paul Snively在2012年Strange Loop上的一个示例):
// 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这样的库中给出一个具体的例子,几天前我写了以下内容作为快速回答this question的首次尝试:
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]
我很惊讶地发现,这个针对HList
的类型级别unique
实现并没有起作用,因为Shapeless可以在后一种情况下轻松找到FilterAux
实例。换句话说,即使你可能不希望如下代码编译,它也会通过:
implicitly[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]
在这种情况下,我看到的是一个bug,或者至少是类似bug的东西,而且已经被修复。
更一般地说,我们可以想象希望检查类似于单元测试的不变性,这些不变性隐含在我的期望中,即
FilterAux
应该如何工作,尽管这听起来很奇怪,因为最近有关类型和测试相对优点的辩论。我的问题是,我不知道是否有任何测试框架(适用于任何平台),允许程序员断言某些内容不能编译。
对于FilterAux
情况,我能想到的一种方法是使用旧的具有空默认值的隐式参数技巧:
def assertNoInstanceOf[T](implicit instance: T = null) = assert(instance == null)
这将使您在单元测试中可以编写以下内容:
assertNoInstanceOf[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]
以下内容更加方便和表达自如,虽然有些麻烦:
assertDoesntCompile(('a' :: 'b' :: HNil).unique[Char])
我想要这个。我的问题是是否有人知道任何测试库或框架支持类似的东西 - 最好是针对Scala,但我会接受任何东西。