在Scala中将对象定义为对其他两个对象的操作
我正在大学的一个实验室用Scala实现符号分析。 要做到这一点,我需要对抽象值进行运算,例如在Scala中将对象定义为对其他两个对象的操作,scala,Scala,我正在大学的一个实验室用Scala实现符号分析。 要做到这一点,我需要对抽象值进行运算,例如Pos,Neg,Zero, NonPos,NonNeg。。。所以我必须声明方法+,-,*,/等等。。。在…上 那些抽象的价值观。我实际上不需要定义所有的东西 成对,但可以在Pos、Neg和Zero上定义操作的“核心”, 然后使用上界定义,例如: NonPos + Pos = leastUpperBound(Zero + Pos, Neg + Pos) 例如,leastUpperBound(零,负)=No
Pos
,Neg
,Zero
,
NonPos
,NonNeg
。。。所以我必须声明方法+
,-
,*
,/
等等。。。在…上
那些抽象的价值观。我实际上不需要定义所有的东西
成对,但可以在Pos
、Neg
和Zero
上定义操作的“核心”,
然后使用上界定义,例如:
NonPos + Pos = leastUpperBound(Zero + Pos, Neg + Pos)
例如,leastUpperBound(零,负)=NonPos
在Scala中,我使用case对象来表示值,并具有
leastUpperBound()
方法对它们中的每一个都执行。但我还有一些代码
我无法消除的重复,例如,我定义:
case object NonNeg extends Sign {
def +(other: Sign) = leastUpperBound(Zero + other, Pos + other)
def -(other: Sign) = ...
def * = ...
...
}
而我也必须做同样的事情:
case object NonPos extends Sign {
def +(other: Sign) = leastUpperBound(Zero + other, Neg + other)
...
}
再说一遍:
case object NonZero extends Sign {
def +(other: Sign) = leastUpperBound(Neg + other, Neg + other)
...
}
我想知道是否有可能有某种“类型工厂”,这样我就可以
本着以下精神说点什么:
case object NonNeg extends UpperBoundSign[Pos, Zero]
我的直觉是,如果Pos
和Zero
是object
s,这是不可能的,
但我对Scala不太熟悉,所以我可能会忘记一些可能会
请允许我这样做
有没有人知道如何删除此重复项?
2.10中的Scala宏是否适合解决这个问题
我希望问题很清楚,
多谢各位
编辑:多亏@cmbaxter的回答和我的一些重构,我想出了一个我喜欢的解决方案。如果有人对它感兴趣,可以在那里找到:。我认为您可能混淆了类型标识符和类实例。我相信,为了获得您想要的功能,您需要将
UpperBoundSign
定义为一个抽象类,使用两个构造函数参数,而不是一个具有两个类型标识符槽的泛型类型。这里有一个过于简单的解决方案选项,可以满足您的需要。如果这完全不是您想要的,我深表歉意:
trait Sign{
def +(other: Sign):Sign
}
abstract class UpperBoundSign(pos:Sign, neg:Sign) extends Sign{
def leastUpperBound(pos:Sign, neg:Sign):Sign
def +(other: Sign) = leastUpperBound(pos + other, neg + other)
}
case object Pos extends Sign{
def +(other:Sign) = ...
}
case object Neg extends Sign{
def +(other:Sign) = ...
}
case object NonNeg extends UpperBoundSign(Pos, Neg){
def leastUpperBound(pos:Sign, neg:Sign) = ...
}
你可以试试集合论
abstract class Sign(name: String) {
def contains(sign: Sign) = sign eq this
def +(other: Sign) = findSign(Union(this, other))
def -(other: Sign) = findSign(Difference(this, other))
def equals(other: Sign) = (contains(Pos), contains(Neg), contains(Zero)) == (other.contains(Pos), other.contains(Neg), other.contains(Zero))
override def equals(other: Any) = {
if(other.isInstanceOf[Sign]) equals(other.asInstanceOf[Sign])
else false
}
override def toString = name
}
case class Union(sign1: Sign, sign2: Sign, name: String = "Union") extends Sign(name) {
override def contains(sign: Sign) = sign1.contains(sign) || sign2.contains(sign)
}
case class Intersection(sign1: Sign, sign2: Sign, name: String = "Intersection") extends Sign(name) {
override def contains(sign: Sign) = (sign1.contains(sign) || sign2.contains(sign)) && !(sign1.contains(sign) && sign2.contains(sign))
}
case class Difference(sign1: Sign, sign2: Sign, name: String = "Difference") extends Sign(name) {
override def contains(sign: Sign) = sign1.contains(sign) && !sign2.contains(sign)
}
case class Negation(sign: Sign, name: String = "Negation") extends Sign(name) {
override def contains(s: Sign) = !sign.contains(s)
}
case object Zero extends Sign("Zero")
case object Pos extends Sign("Pos")
case object Neg extends Sign("Neg")
val NonPos = Negation(Pos, "NonPos")
val NonNeg = Negation(Neg, "NonNeg")
val NonZero = Negation(Zero, "NonZero")
val AnySign = Union(NonZero, Zero, "AnySign")
val NoSign = Negation(AnySign, "NoSign")
val signs = List(Zero, Pos, Neg, NonPos, NonNeg, NonZero, AnySign, NoSign)
def findSign(sign: Sign) = signs.find(_ == sign).get
println(Pos + Neg)
println(NonNeg - Zero)
println(NonZero + Zero)
println(Pos + Neg + Zero)
println(NonPos - Neg - Zero)
好的,对不起,我误解了你的问题 不管怎样,我试过你的代码,它看起来很有趣,但因为我喜欢简单,所以我试着为你的问题想出一个更简单的解决方案
object Sign {
case object Pos extends Sign
case object Neg extends Sign
case object Zero extends Sign
case object Undefined extends Sign
case object NonPos extends SignSet(Set(Neg, Zero)) {
override def toString = "NonPos"
}
case object NonNeg extends SignSet(Set(Pos, Zero)) {
override def toString = "NonNeg"
}
case object NonZero extends SignSet(Set(Pos, Neg)) {
override def toString = "NonZero"
}
case object AnySign extends SignSet(Set(Pos, Neg, Zero)) {
override def toString = "AnySign"
}
private val signs = List(Pos, Neg, Zero, Undefined, NonPos, NonNeg, NonZero, AnySign)
private def calc(op: Symbol, s1: Sign, s2: Sign): Sign = {
val sign = _calc(op, s1, s2)
signs.find(_ == sign).getOrElse(sign)
}
private def _calc(op: Symbol, s1: Sign, s2: Sign): Sign = (op, s1, s2) match {
case (op, set: SignSet, sign) => set.flatMap(s => _calc(op, s, sign))
case (op, sign, set: SignSet) => set.flatMap(s => _calc(op, sign, s))
case (_, Undefined, _) => Undefined
case (_, _, Undefined) => Undefined
case ('+, x, y) if x == y => x
case ('+, x, Zero) => x
case ('+, Zero, x) => x
case ('+, Pos, Neg) => SignSet(Pos, Neg, Zero)
case ('+, Neg, Pos) => SignSet(Pos, Neg, Zero)
case ('-, x, Neg) => _calc('+, x, Pos)
case ('-, x, Pos) => _calc('+, x, Neg)
case ('-, x, Zero) => x
case ('*, Zero, _) => Zero
case ('*, Pos, x) => x
case ('*, Neg, Pos) => Neg
case ('*, Neg, Neg) => Pos
case ('*, Neg, Zero) => Zero
case ('/, _, Zero) => Undefined
case ('/, x, y) => _calc('*, x, y)
}
}
sealed trait Sign {
import Sign.calc
def +(other: Sign) = calc('+, this, other)
def -(other: Sign) = calc('-, this, other)
def *(other: Sign) = calc('*, this, other)
def /(other: Sign) = calc('/, this, other)
def flatten: Sign = this
def |(other: Sign): Sign = other match {
case sign if sign == this => this
case SignSet(signs) => SignSet(signs + this)
case sign => SignSet(this, sign)
}
}
object SignSet {
def apply(signs: Set[Sign]) = new SignSet(signs)
def apply(signs: Sign*) = new SignSet(signs.toSet)
def unapply(set: SignSet) = Some(set.signs)
}
class SignSet(val signs: Set[Sign]) extends Sign {
def flatMap(f: Sign => Sign) = SignSet(signs.map(f)).flatten
override def flatten = signs.map(_.flatten).reduce(_ | _)
override def |(other: Sign) = other match {
case SignSet(otherSigns) => SignSet(otherSigns | signs)
case sign => SignSet(signs + sign)
}
override def toString = signs.mkString("SignSet(", ", ", ")")
def equals(other: SignSet) = signs == other.signs
override def equals(other: Any) = other match {
case set: SignSet => equals(set)
case _ => false
}
}
import Sign._
println(Pos / NonPos)
println(Pos + Neg)
println(NonZero * Zero)
println(NonZero / NonPos)
println(NonZero - NonZero)
println(NonZero + Zero)
多谢了,我不知道我们可以这样继承遗产,今晚我就不那么无知地上床睡觉了。我认为这将非常完美,我甚至可以使用
列表[Sign]
作为上限符号
的参数来仲裁大量类型。谢谢,也许我对潜在问题不是很清楚,但我想做的是,在给定操作数符号的情况下,以安全的方式给出操作结果的符号。例如,NonZero+Zero=NonZero
将0添加到非空数字不能使其为空。所以这不是你的建议,但是谢谢你的尝试!如果你感兴趣的话,我会把我在主要问题中提出的要点贴出来。谢谢,这确实简单且短得多。实际上,最大的好处可能是,当将Pos
与未定义的连接时,它具有更好的精度。例如,我以前发布的解决方案将失去精度(说它可以是任何东西),而您的解决方案不会。此外,这让我想起了Scala中存在的符号,感谢您花时间发布这篇文章!