Chr*_*rle 7 types scala inference mixins
我有一个关于有限排列集的代数群的用例.因为我想将这个组用于各种不相关的排列类,我想把它作为一个混合特性来做.这是我尝试的摘录
trait Permutation[P <: Permutation[P]] { this: P =>
def +(that: P): P
//final override def equals(that: Any) = ...
//final override lazy val hashCode = ...
// Lots of other stuff
}
object Permutation {
trait Sum[P <: Permutation[P]] extends Permutation[P] { this: P =>
val perm1, perm2: P
// Lots of other stuff
}
private object Sum {
def unapply[P <: Permutation[P]](s: Sum[P]): Some[(P, P)] = Some(s.perm1, s.perm2)
//def unapply(s: Sum[_ <: Permutation[_]]): Some[(Permutation[_], Permutation[_])] = Some(s.perm1, s.perm2)
}
private def simplify[P <: Permutation[P]](p: P): P = {
p match {
case Sum(a, Sum(b, c)) => simplify(simplify(a + b) + c)
// Lots of other rules
case _ => p
}
}
}
Run Code Online (Sandbox Code Playgroud)
在某个时间点,我想调用简化方法,以便使用代数公理简化组操作的表达式.使用模式匹配似乎是有意义的,因为有很多公理需要评估,语法简洁.但是,如果我编译代码,我得到:
error: inferred type arguments [P] do not conform to method unapply's type parameter bounds [P <: Permutation[P]]
Run Code Online (Sandbox Code Playgroud)
我不明白为什么编译器无法正确推断类型,我不知道如何帮助它.实际上,在这种情况下,当模式匹配时,P的参数类型是无关紧要的.如果p是任何排列和,则模式应该匹配.返回类型仍然是P,因为转换仅通过调用P上的+运算符来完成.
因此,在第二次尝试中,我交换了注释掉的unapply版本.但是,我从编译器(2.8.2)得到一个断言错误:
assertion failed: Sum((a @ _), (b @ _)) ==> Permutation.Sum.unapply(<unapply-selector>) <unapply> ((a @ _), (b @ _)), pt = Permutation[?>: Nothing <: Any]
Run Code Online (Sandbox Code Playgroud)
有什么线索我怎么能让编译器接受这个?
提前致谢!
经过两天的研究,我终于找到了一个可以在没有警告的情况下编译并通过我的规范测试的解决方案。以下是我的代码的可编译摘录,以显示所需内容。但请注意,该代码是无操作的,因为我省略了实际执行排列的部分:
/**
* A generic mix-in for permutations.
* <p>
* The <code>+</code> operator (and the apply function) is defined as the
* concatenation of this permutation and another permutation.
* This operator is called the group operator because it forms an algebraic
* group on the set of all moves.
* Note that this group is not abelian, that is the group operator is not
* commutative.
* <p>
* The <code>*</code> operator is the concatenation of a move with itself for
* <code>n</code> times, where <code>n</code> is an integer.
* This operator is called the scalar operator because the following subset(!)
* of the axioms for an algebraic module apply to it:
* <ul>
* <li>the operation is associative,
* that is (a*x)*y = a*(x*y)
* for any move a and any integers x and y.
* <li>the operation is a group homomorphism from integers to moves,
* that is a*(x+y) = a*x + a*y
* for any move a and any integers x and y.
* <li>the operation has one as its neutral element,
* that is a*1 = m for any move a.
* </ul>
*
* @param <P> The target type which represents the permutation resulting from
* mixing in this trait.
* @see Move3Spec for details of the specification.
*/
trait Permutation[P <: Permutation[P]] { this: P =>
def identity: P
def *(that: Int): P
def +(that: P): P
def unary_- : P
final def -(that: P) = this + -that
final def unary_+ = this
def simplify = this
/** Succeeds iff `that` is another permutation with an equivalent sequence. */
/*final*/ override def equals(that: Any): Boolean // = code omitted
/** Is consistent with equals. */
/*final*/ override def hashCode: Int // = code omitted
// Lots of other stuff: The term string, the permutation sequence, the order etc.
}
object Permutation {
trait Identity[P <: Permutation[P]] extends Permutation[P] { this: P =>
final override def identity = this
// Lots of other stuff.
}
trait Product[P <: Permutation[P]] extends Permutation[P] { this: P =>
val perm: P
val scalar: Int
final override lazy val simplify = simplifyTop(perm.simplify * scalar)
// Lots of other stuff.
}
trait Sum[P <: Permutation[P]] extends Permutation[P] { this: P =>
val perm1, perm2: P
final override lazy val simplify = simplifyTop(perm1.simplify + perm2.simplify)
// Lots of other stuff.
}
trait Inverse[P <: Permutation[P]] extends Permutation[P] { this: P =>
val perm: P
final override lazy val simplify = simplifyTop(-perm.simplify)
// Lots of other stuff.
}
private def simplifyTop[P <: Permutation[P]](p: P): P = {
// This is the prelude required to make the extraction work.
type Pr = Product[_ <: P]
type Su = Sum[_ <: P]
type In = Inverse[_ <: P]
object Pr { def unapply(p: Pr) = Some(p.perm, p.scalar) }
object Su { def unapply(s: Su) = Some(s.perm1, s.perm2) }
object In { def unapply(i: In) = Some(i.perm) }
import Permutation.{simplifyTop => s}
// Finally, here comes the pattern matching and the transformation of the
// composed permutation term.
// See how expressive and concise the code is - this is where Scala really
// shines!
p match {
case Pr(Pr(a, x), y) => s(a*(x*y))
case Su(Pr(a, x), Pr(b, y)) if a == b => s(a*(x + y))
case Su(a, Su(b, c)) => s(s(a + b) + c)
case In(Pr(a, x)) => s(s(-a)*x)
case In(a) if a == a.identity => a.identity
// Lots of other rules
case _ => p
}
} ensuring (_ == p)
// Lots of other stuff
}
/** Here's a simple application of the mix-in. */
class Foo extends Permutation[Foo] {
import Foo._
def identity: Foo = Identity
def *(that: Int): Foo = new Product(this, that)
def +(that: Foo): Foo = new Sum(this, that)
lazy val unary_- : Foo = new Inverse(this)
// Lots of other stuff
}
object Foo {
private object Identity
extends Foo with Permutation.Identity[Foo]
private class Product(val perm: Foo, val scalar: Int)
extends Foo with Permutation.Product[Foo]
private class Sum(val perm1: Foo, val perm2: Foo)
extends Foo with Permutation.Sum[Foo]
private class Inverse(val perm: Foo)
extends Foo with Permutation.Inverse[Foo]
// Lots of other stuff
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,解决方案是定义 SimplyTop 方法的本地类型和提取器对象。
我还提供了一个小示例,说明如何将此类混合应用到 Foo 类。正如您所看到的,Foo 只不过是一个用于其自身类型的组合排列的工厂。如果您有许多这样的原本不相关的类,那么这是一个很大的好处。
<咆哮>
然而,我不得不说 Scala 的类型系统极其复杂!我是一位经验丰富的 Java 库开发人员,并且对 Java 泛型非常精通。然而我花了两天时间才弄清楚包含三种类型和对象定义的六行代码!如果这不是出于教育目的,我就会放弃这种方法。
现在,我很想预言,由于 Scala 的复杂性,它不会成为编程语言的下一个重大事件。如果您是一名 Java 开发人员,现在对 Java 泛型感到有点不舒服(不是我),那么您会讨厌 Scala 的类型系统,因为至少可以说,它在 Java 泛型的概念中添加了不变量、协变和逆变。
总而言之,Scala 的类型系统似乎面向更多的科学家而不是开发人员。从科学的角度来看,推理程序的类型安全性是件好事。从开发人员的角度来看,弄清楚这些细节的时间是浪费的,因为这使他们远离了程序的功能方面。
没关系,我肯定会继续使用 Scala。模式匹配、混合和高阶函数的组合太强大了,不容错过。然而,我认为如果没有过于复杂的类型系统,Scala 将是一种更加高效的语言。
</咆哮>
| 归档时间: |
|
| 查看次数: |
445 次 |
| 最近记录: |