scala - 如何确保元组是同质的?
问题描述
由于我无法控制的原因,我的方法以元组的形式接收输入。这个元组应该只包含 的实例Foo
,即它应该看起来像(Foo, Foo ... Foo)
并且不应该有String
orInt
在里面。我想在编译时检查这一点,而不是在运行时抛出异常。我怎样才能做到这一点?
以下是我目前拥有的代码,这是不正确的:
def f(tupleOfFoos: Tuple): Tuple = {
for (x <- tupleOfFoos) assert(x.isInstanceOf[Foo])
mapTuple(tupleOfFoos, irrelevantFunction)
}
我愿意使用 Shapeless 或 Dotty/Scala 3 中引入的新功能。
解决方案
在 Scala 2 中,使用 Shapeless,您可以这样做 ( Scastie ):
def f[T <: Product, H <: HList](tupleOfFoos: T)(
implicit gen: Generic.Aux[T, H],
hev: LiftAll[({type E[T] = Foo =:= T})#E, H]
) = tupleOfFoos
LiftAll
确保有Foo =:= X
for each X
in的实例H
,并gen
确保T
andH
不是完全不相关的类型。
在 Dotty 中,您可以为此添加具有匹配类型的证据参数:
type Homogenous[H, T <: Tuple] = T match {
case EmptyTuple => DummyImplicit
case H *: t => Homogenous[H, t]
case _ => Nothing
}
def f[T <: Tuple](tupleOfFoos: T)(using Homogenous[Foo, T]) = tupleOfFoos
这将允许你打电话f((Foo(), Foo(), Foo()))
,但不能f((1, 2, 3))
。
Homogenous
是一个递归匹配类型,其基本情况为EmptyTuple
. 如果一个元组是空的,那么它没有被非 s 填充Foo
,所以类型变为DummyImplicit
,它已经在范围内隐含。否则,我们检查它是否看起来像(H, ...)
/ H *: t
,在这种情况下,我们需要检查元组的其余部分 ( t
) 是否也有效。如果它不匹配第二种情况,我们知道元组是无效的,在这种情况下结果是Nothing
,理智的人不会隐含值。
如果你想使用上下文边界,你可以做一个额外的柯里化类型(Scastie):
type Homo2[H] = [T <: Tuple] =>> Homogenous[H, T]
def f[T <: Tuple : Homo2[Foo]](tupleOfFoos: T) = tupleOfFoos
不幸的是,我无法让它与单一的咖喱类型(Scastie)一起工作:
type Homogenous[H] = [T <: Tuple] =>> T match {
case EmptyTuple => DummyImplicit
case H *: t => Homogenous[H][t]
case _ => Nothing
}
推荐阅读
- android - 即使在 gradle 构建完成后,Android 应用程序也无法在模拟器上运行
- c# - 如何在 ASP.NET MVC HTML 音频播放器中播放大文件 500Мb?
- python-3.x - 由于用户权限,TensorFlow 安装被拒绝
- javascript - 单选按钮作为图像,onclick 到下一个字段集
- javascript - Google Maps Api:无法点击数据层后面的可点击多边形
- python - 在 macOS 上将 TLS 1.0 升级到 TLS 1.2
- javascript - 使用 JavaScript 更改 HTML 中的特定单词
- javascript - 用于文件上传进度的 ajax 监听器
- pandas - 通过将一些值移动到列中,将行规范化为唯一行
- c++ - std::aligned_storage 的目的是什么?