【问题标题】:"Intersection types" in ScalaScala 中的“交叉点类型”
【发布时间】:2016-06-18 14:15:20
【问题描述】:

我知道 Scala 不支持“联合类型”,但是交集类型呢?

简而言之,我想要一个这样的函数:

def intersect[A,B,C](a: A, b: B): C = ??? // a & b

或者一个方法:

class A {
    def intersect[B, C](b: B): C = ??? // this & b
}

A 和B 共享一个共同的超类,确保相交操作的有效性,而C 将是A 或B 交集处的类型。

在我的用例中,A 或 B 代表变量或常量(相同类型)。我想从类中区分一个常量和一个具有单例域的变量。如果我尝试将一个集合与一个值相交,我会返回该值(或者如果该值不在集合中,则返回空集/抛出异常)。

这是预期输出的示例:

trait IntExpression {
  // Correct signature to be determined
  def intersect [A <: IntExpression, B <: A & this.type] (that: A): B
}
case class IntVariable(domain: Seq[Int]) extends IntExpression
case class IntConstant(value: Int) extends IntExpression

val a = IntVariable(1,2,3)
val b = IntVariable(2,3,4)
val c = IntConstant(2)

然后:

a intersect b == b intersect a == IntVariable(2,3)
a intersect c == c intersect a == IntConstant(2)

【问题讨论】:

  • 也许你可以写一个宏来派生这样的集合?只要它可以访问类层次结构,就应该可以。
  • 我不太明白您期望的输出。您能否举例说明可能的输入值和预期输出?
  • 我没有看到这个用例。为什么不直接使用集合?
  • 我想为约束规划求解器实现 DSL。我指的是现有的外部 DSL,它将变量与常量区分开来。甚至存在第三种类型的表达式,它表示一系列表达式(并且很难与类型系统的其余部分统一:()这种区别通常很有用,因为它可以导致有趣的优化。它们也可以通过检查来触发域大小,但我想在我的系统中使用模式匹配和额外的类型安全。
  • 如果你想指定一个类型是A和B的子类型,写A with B。

标签: scala types intersection


【解决方案1】:

正如上面正确描述的 ziggystar:A &amp; B 在 Scala 中是 A with B。

关于您想在运行时创建伴随类型 C 的事实,您必须根据在 A 和 B 中获得的类型在运行时创建此类型。

这个问题的解决方案,或者至少是一个线索,你可以在How to mix-in a trait to instance?找到。

但是,您在用例中需要的是http://en.wikipedia.org/wiki/Dependent_type 的情况。尽管 Scala 不支持依赖类型,但您可以随时尝试 Agda ;)

【讨论】:

    【解决方案2】:

    我使用++ 作为实现,因为它就在那里。并且Set 上的intersect 不起作用,因为Set 是不变的。如果这没有意义,请忽略它。

    def intersect[C, A <: C, B <: C](as: Seq[A], bs: Seq[B]): Seq[C] = as ++ bs
    

    【讨论】:

    • 这是错误的。 intersect(Seq(1,2,3), Seq(2,3,4)) == Seq(1,2,3,2,3,4) op 正在寻找 Seq(2,3) 的结果
    猜你喜欢
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 2018-03-22
    • 2020-01-03
    • 2013-01-22
    • 2023-02-21
    • 2014-08-10
    • 1970-01-01
    相关资源
    最近更新 更多