4

どうやらエクストラクタオブジェクトのunapply/unapplySeqは、暗黙のパラメータをサポートしていません。ここで、興味深いパラメータaと、cを抽出するときに隠れておくとよい不穏に遍在するパラメータbを想定します。

[編集]:これを引き起こした私のintellij/scala-pluginインストールで何かが壊れているようです。私は説明できません。私は最近、私のIntellijで多くの奇妙な問題を抱えていました。再インストールした後、問題を再現できなくなりました。unapply / unapplySeqが暗黙のパラメーターを許可することを確認しました!ご協力いただきありがとうございます。

これは機能しません(**編集:はい、機能します):**

trait A; trait C; trait B { def getC(a: A): C }

def unapply(a:A)(implicit b:B):Option[C] = Option(b.getC(a))

理想的なエクストラクタがどのようなものであるかを理解していると、Javaの人々にも直感的に意図が明確になりますが、この制限により、追加のパラメータに依存するエクストラクタオブジェクトが基本的に禁止されます。

通常、この制限をどのように処理しますか?

これまでのところ、私はそれらの4つの可能な解決策を持っています:

1)私が改善したい最も簡単な解決策:bを非表示にしないで、タプルの形式でunapplyの通常のパラメーターとして、パラメーターbをaと一緒に提供します。

object A1{ 
    def unapply(a:(A,B)):Option[C] = Option(a._2.getC(a._1)) }

クライアントコード:

 val c1 = (a,b) match { case A1(c) => c1 }

ここではaからcへの脱構築が重要であるということを逸脱するノイズが多いので、私はそれが好きではありません。また、このscalaコードを実際に使用することを確信しなければならないJavaの人々は、1つの追加の合成ノベルティ(タプルブレース)に直面しています。彼らは反スカラ攻撃性を得るかもしれません「これは何ですか?...では、そもそも通常の方法を使用して、確認してみませんか?」

2)特定のBへの依存関係をカプセル化するクラス内にエクストラクタを定義し、そのインスタンスのエクストラクタをインポートします。インポートサイトではJavaの人々にとっては少し珍しいですが、パターンマッチではサイトbがうまく隠されており、何が起こっているのかが直感的にわかります。お気に入り。私が逃したいくつかの不利な点は?

class BDependent(b:B){ 
   object A2{ 
    def unapply(a:A):Option[C] = Option(b.getC(a))
         } }

クライアントコードでの使用法:

val bDeps = new BDependent(someB)
import bDeps.A2 
val a:A = ...
val c2 = a match { case A2(c) => c }
}

3)クライアントコードのスコープでエクストラクタオブジェクトを宣言します。bは、ローカルスコープで「b」を使用できるため非表示になっています。コードの再利用を妨げ、クライアントコードをひどく汚染します(さらに、コードを使用する前にコードを記述する必要があります)。

4)関数B => Cのオプションを適用せずに返します。これにより、bをエクストラクターに直接提供するのではなく、使用した場合の結果に、野心的なパラメーターに依存するエクストラクターのインポートと使用が可能になります。Javaの人々は、関数値の使用法に混乱している可能性があります。bは非表示ではありません。

 object A4{
  def unapply[A,C](a:A):Option[B => C] = Option((_:B).getC(a))
   }

次に、クライアントコードで:

 val b:B = ...
 val soonAC: B => C = a match { case A4(x) => x }
 val d = soonAC(b).getD ...

さらなる備考:

  • この回答で示唆されているように、「ビュー境界」は、エクストラクタを暗黙の変換で機能させるのに役立つ場合がありますが、これは暗黙のパラメータでは役立ちません。何らかの理由で、暗黙の変換を回避したくない。
  • 「文脈の限界」を調べましたが、同じ制限があるようですよね?
4

2 に答える 2

4

コードの最初の行はどのような意味で機能しませんか?エクストラクタメソッドの暗黙的なパラメータリストに恣意的な禁止事項はありません。

次の設定を検討してください(ここで余分な魔法が発生していないことを示すために、ケースクラスの代わりにプレーンな古いクラスを使用しています):

class A(val i: Int)
class C(val x: String)
class B(pre: String) { def getC(a: A) = new C(pre + a.i.toString) }

次に、暗黙の値を定義し、メソッドBを使用してエクストラクタオブジェクトを作成します。unapply

implicit val b = new B("prefix: ")

object D {
  def unapply(a: A)(implicit b: B): Option[C] = Option(b getC a)
}

このように使用できます:

scala> val D(c) = new A(42)
c: C = C@52394fb3

scala> c.x
res0: String = prefix: 42

まさに私たちが期待する通りです。ここで回避策が必要な理由がわかりません。

于 2012-09-09T11:40:22.743 に答える
1

あなたが抱えている問題は、暗黙のパラメータがコンパイル時(静的)の制約であるのに対し、パターンマッチングは実行時(動的)のアプローチであるということです。

trait A; trait C; trait B { def getC(a: A): C }

object Extractor {
  def unapply(a: A)(implicit b: B): Option[C] = Some(b.getC(a))
}

// compiles (implicit is statically provided)
def withImplicit(a: A)(implicit b: B) : Option[C] = a match { 
  case Extractor(c) => Some(c)
  case _            => None
}

// does not compile
def withoutImplicit(a: A) : Option[C] = a match { 
  case Extractor(c) => Some(c)
  case _            => None
}

したがって、これは概念的な問題であり、解決策は実際に何を達成したいかによって異なります。オプションの暗黙の行に沿って何かが必要な場合は、次を使用できます。

sealed trait FallbackNone {
  implicit object None extends Optional[Nothing] {
    def toOption = scala.None
  }
}
object Optional extends FallbackNone {
  implicit def some[A](implicit a: A) = Some(a)
  final case class Some[A](a: A) extends Optional[A] { 
    def toOption = scala.Some(a)
  }
}
sealed trait Optional[+A] { def toOption: Option[A]}

それからあなたが持っていた場所はあなたが持ってimplicit b: Bいるでしょうimplicit b: Optional[B]

object Extractor {
   def unapply(a:A)(implicit b: Optional[B]):Option[C] = 
      b.toOption.map(_.getC(a))
}

def test(a: A)(implicit b: Optional[B]) : Option[C] = a match { 
   case Extractor(c) => Some(c)
   case _            => None
}

そして、次の両方がコンパイルされます。

test(new A {}) // None

{
  implicit object BImpl extends B { def getC(a: A) = new C {} }
  test(new A {}) // Some(...)
}
于 2012-09-09T11:52:19.637 に答える