1

操作を宣言する同じトレイトをすべて共有する複数の算術システムを実装するために必要な型シグネチャを Scala で宣言するにはどうすればよいでしょうか? 基本的な特性/クラスにいくつかのヘルパー実装を追加しようとするまで、解決したと思っていました。次のコード スニペット (コンパイル) では、sq() が、より明白な this*this ではなく、this*self として定義されていることに注意してください。また、self() もトレイトに実装できません (具体的な拡張クラスに到達するまで待たなければなりません)。

trait NumberBase [NUMBERTYPE <: NumberBase[NUMBERTYPE]] {
   // type NUMBERTYPE >: this.type
   def *(that: NUMBERTYPE):NUMBERTYPE
   def self:NUMBERTYPE
   def sq:NUMBERTYPE = { this*self }
}

class D(val v:Double) extends NumberBase[D] {
   def self:D = { this }
   def *(that: D):D = { new D(this.v*that.v) }
}

質問/目標は次のとおりです: D の * の型シグネチャを変更せずに、self() または (少なくとも self() の実装を NumberBase に移動する) の使用を削除します。上記のリンクの多くの修正により、派生クラスが作成されます。実装不可能 (new D() が * によって返される型ではない、または * が D で推測できない型シグネチャを持っているなど)。一部の署名が醜くなってもかまいませんが、このコードが表現することをコードで表現したいと思います。つまり、派生クラスは独自の型でのみ機能し、独自の型のインスタンスを返します (上下に移動していません)。階層で)。

ここでいくつかの問題をリストした議論を見つけました (ただし、解決策はありません): http://www.scala-lang.org/node/839。基本クラスと実装の両方が表示されるまで、いくつかの問題に遭遇することはありません。

上記の回避策 (実装クラスに self() の実装を強制する) を含む完全なコードは、https ://github.com/WinVector/AutoDiffに記載されています。さまざまな算術実装で汎用的な関数を作成する。これにより、標準の機械演算 (D など) やその他のもの (副作用として勾配を計算する数値システムなど) のラッピングを使用できます。

4

1 に答える 1

3

セルフタイプを使用したいと思います。これにより、インスタンスタイプのインスタンスになりNumberBase[N]ます。N

trait NumberBase[N <: NumberBase[N]] { this: N =>
  def *(that: N): N
  def sq: N = this * this
}

class D(val v: Double) extends NumberBase[D] {
  def *(that: D): D = new D(this.v * that.v)
}

val a = new D(0.5)
val b = new D(0.25)

a * b  // D(0.125)
a.sq   // D(0.25)

ただし、本当に新しいタイプの数値を定義したい場合は、Scalaライブラリ自体が行うことを実行し、型クラスを使用する必要がありますNumeric

于 2012-09-23T21:53:45.667 に答える