4

大学の研究室で Scala で符号分析を実装しています。これを行うには、 、 、 、 、 などの抽象値の算術演算が必要PosですNegZeroしたがって NonPos、これらの抽象値でメソッド、、などNonNegを宣言する必要があります。実際には、ペアごとにすべてを定義する必要はありませんが、 、、およびに対する操作の「コア」を定義し、上限を使用して定義できます。次に例を示します。+-*/PosNegZero

NonPos + Pos = leastUpperBound(Zero + Pos, Neg + Pos)

たとえばどこでleastUpperBound(Zero, Neg) = 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]

私の直感では、PosandZeroobjects であるとそれは不可能だろうということですが、私は Scala にあまり詳しくないので、それを可能にする機能やパターンを忘れているかもしれません。

この重複を削除するためのアイデアはありますか? 2.10 の Scala マクロは、この問題に適しているのでしょうか?

質問が明確であることを願っています、ありがとう。

編集: @cmbaxter の回答と私の一部のリファクタリングのおかげで、私は好きな解決策を思いつきました。興味がある人は、 https ://gist.github.com/Ricordel/5553405 で見つけることができます。

4

3 に答える 3

1

わかりました、申し訳ありませんが、あなたの質問を誤解しました とにかく、私はあなたのコードを試してみましたが、それは非常に興味深いように見えますが、シンプルさが好きなので、あなたの問題に対するより簡単な解決策を考え出そうとしました.

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)
于 2013-05-10T18:01:51.020 に答える