1

以下をScalaで書きたいと思います。

def method(a: Float, b: Float, c: Float) = {
  if( a < b <= c) {
    ...
  }
}

現在、これは有効ではありません。確かにa < b、ブール値を返します。これは、比較のために でラップされていbooleanWrapperます。Floatコンパイラは、 c の型が ではなく であると不平を言うBooleanため、 とはまったく比較bcれません。

これを実現するために、暗黙のクラス、メソッド、および値クラスを使用することは可能でしょうか?

今のところ、次のことしかできませんでした。

class Less(val previous: Boolean, last: Float) {
  def <=(other: Float): Less = new Less(previous && last <= other, other)
  def <(other: Float): Less = new Less(previous && last < other, other)
}
implicit def f(v: Float): Less = {
  new Less(true, v)
}
implicit def lessToBoolean(f: Less): Boolean = {
  f.previous
}

def method(a: Float, b: Float, c: Float) = {
  if( f(a) < b <= c) {
    ...
  }
}

標準的なトリックを使用してこの f を削除する方法はありますか?

4

2 に答える 2

3

はい、暗黙的およびカスタム演算子でこれをエミュレートできます。以下に短い例を示します。

implicit class FloatWrapper(n:Float) {
  def :<(that:Float) = ResultAndLastItem(n<that, that)
  def :>(that:Float) = ResultAndLastItem(n>that, that)
  def :=(that:Float) = ResultAndLastItem(n==that, that)
  // insert more comparison operations here
}

case class ResultAndLastItem(result:Boolean, lastItem:Float) extends FloatWrapper(lastItem) {
  // insert boolean operations here
  // boolean operations should return another instance of ResultAndLastItem (?)
}

implicit def toBoolean(r:ResultAndLastItem):Boolean = r.result

REPL での使用例を次に示します。

Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_45).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :paste
// Entering paste mode (ctrl-D to finish)

implicit class FloatWrapper(n:Float) {
  def :<(that:Float) = ResultAndLastItem(n<that, that)
  def :>(that:Float) = ResultAndLastItem(n>that, that)
  def :=(that:Float) = ResultAndLastItem(n==that, that)
  // insert more comparison operations here
}

case class ResultAndLastItem(result:Boolean, lastItem:Float) extends FloatWrapper(lastItem) {
  // insert boolean operations here
  // boolean operations should return another instance of ResultAndLastItem (?)
}

implicit def toBoolean(r:ResultAndLastItem):Boolean = r.result

// Exiting paste mode, now interpreting.

warning: there were 1 feature warnings; re-run with -feature for details
defined class FloatWrapper
defined class ResultAndLastItem
toBoolean: (r: ResultAndLastItem)Boolean

scala> if(2 :< 3 :< 4) "yay" else "nope"
res0: String = yay

scala> if(2 :< 3 :< 3) "nope" else "yay"
res1: String = yay

備考:

  • などの比較演算子を簡単に追加できます:<=

  • implicit classカスタム演算子を使用する必要があるのは、コンパイラが s の組み込みの既定の演算子ではなく、上記の演算子を使用することを強制するためですFloat

  • DoubleInt、またはカスタム型など、すべての同等の型を許可するために、私の例をより一般的なものにするのは困難です。これが難しい理由は、implicit class FloatWrapperがそれ以上の引数を必要とできないためですimplicit。暗黙的なものをネストすることはできません。(より正確には、構文的には可能ですが、コンパイラは暗黙的な解決のためにそれらを選択しません。)

  • 最適化として、ブール値のショートカットを追加することを検討することをお勧めします。つまり、式が であることが既にわかっている場合false、残りの比較を評価する必要はありません。

    • ||またはなどのブール演算子も追加すると、これは扱いにくくなります&&
于 2013-06-20T10:10:40.107 に答える