Scala-创建类型集合的惯用方式

问题描述 投票:1回答:1

问题

让我们说我有一个看起来像这样的ADT

sealed trait TT
case class A(...) extends TT
case class B(...) extends TT
case class C(...) extends TT
// ... lot of others

而且我有此函数,它为TT的子集返回true。假设AC

def shouldIPublish(tt: TT): Boolean = ???

我不完美的解决方案

val shouldIPublishPF: PartialFunction[TT, Unit] = {
    case _: A =>
    case _: C =>
} 
def shouldIPublish(tt: TT): Boolean = shouldIPublishPF.isDefinedAt(tt)

我在这里使用部分函数,​​因为实际问题要复杂一些。我使用orElse将几个部分功能组合在一起。

此解决方案易于推论且足够简单。但是,

  • 似乎不是很习惯。我的意思是,该工具(部分函数)似乎不适合该工作(测试类型是否包含在一组类型中)。
  • 我无法获得为偏函数定义的每个值。在这种情况下,它将是AC。将新类型添加到部分函数时,我的单元测试应该失败。

替代品(我能想到)

一组课程

也许是最简单的解决方案。我可以有一个Set并使用.getClass上课。不过看起来很丑。

Set(A.getClass, C.getClass)

无形状副产品

起初看起来很有希望。很习惯。

type ShoudIPublish = A :+: C :+: CNil

[不幸的是,我没有看到如何在ShoudIPublish中测试类型是否“包含”。而且我不知道我们是否可以收集所有类型的列表(此处为AC)。


您有什么建议吗?

scala shapeless category-theory
1个回答
0
投票

类型类看起来像一个解决方案(如果您知道tt的类型,即在编译时为TT的特定子类型)

trait ShouldIPublish[T <: TT]
object ShouldIPublish {
  implicit val a: ShouldIPublish[A] = null
  implicit val c: ShouldIPublish[C] = null
}

def shouldIPublish[T <: TT : ShouldIPublish](tt: T) = ???

shouldIPublish(A())
//  shouldIPublish(B()) // doesn't compile
shouldIPublish(C())

标准类型类别为shapeless.ops.coproduct.Inject

type ShoudIPublish = A :+: C :+: CNil

def shouldIPublish[T <: TT : Inject[ShoudIPublish, *]](tt: T) = ???

shouldIPublish(A())
//  shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
© www.soinside.com 2019 - 2024. All rights reserved.