6

次のようなものが与えられます:

class A {
  def f(x: X) = ...
  def g(y: Y, z: Z) = ...
  ...
}

関数を (自動的に) 抽出する方法:

object A {
  val f' = (a: A, x: X) => a.f(x)  // do this automagically for any arbitrary f
  val g' = (a: A, y: Y, z: Z) => a.g(y, z) // and deal with arity > 1 too
  ...
}

この正確な型シグネチャ (最初にオブジェクト、次にパラメーター リスト) を使用します。問題を非常に明確に述べさせてください。

f(x1: X1, ..., xn: Xn)「クラス のコンテキストで定義されたメソッドが与えられた場合Af'、 (i) のインスタンスを受け取り、(aA ii)のパラメーター リストに 1:1 で対応するパラメーター リスト、つまりを受け取る関数自動的に抽出する方法。実装はまさにfx1: X, ... xn: Xna.f(x1: X1, ..., xn: Xn)

あるいは:

ラムダ計算の拡張性の概念を捉え.λx.(f x)fxf

fこれは、識別子、g、 ... にアクセスする方法を見つけることによって最初に取り組むことができa: AますA。単純に書くことf'g'手で書くこともできますが、DRYness を楽しみましょう。


PS たぶん、これは実行時リフレクションなしでは不可能です (Scala 2.10f以降のマクロでは可能かもしれませんが)。ただし、に頼る必要なしに、次のようなものになります。ga: Astrings

A.getMethod("f"): Function2[A, X, ...]

また、質問を実際に使用すると、参加者が代替案を提案するのに役立つ可能性があることも理解していますが、これについては抽象的な意味で議論しています. 私はこの問題に縮小した他の問題を解決しようとはしていません。これが可能かどうかを知りたいと思っています:-)この質問の背後にある動機を実際に理解するための非常に素晴らしい記事です。

4

3 に答える 3

2

マクロを使用してコンパイル時にこれを行うことは確かに可能です - ScalaMock 3 のプレビュー リリースでは、私はこれと非常によく似ています - モック オブジェクトは、各メンバーがモック関数のインスタンスによって実装される無名クラスのインスタンスです。あなたがやろうとしていることの出発点としてそれを使うことができるかもしれません.

警告: 現在、ScalaMock 3 は Scala 2.10.0-M6 でのみ動作します。M7 や現在の開発バージョンでは動作しません。マクロ API の重大な変更に (まだ!) 対処する機会がなかったからです。

于 2012-10-07T14:37:41.617 に答える
0

これは、Scala ケース クラスのレンズを作成するLensedプロジェクトに似ています。レンズの代わりにあなたが説明した方法を作成するためにそれを変更することは可能だと思います。

于 2012-10-07T20:27:33.993 に答える
-2

これは特に美しいソリューションではないことはわかっていますが、マクロを使用できない場合は、必要なコンパニオンオブジェクトのソースコードを生成し、別のビルドステップでコンパイルできます。

def generateCompanionObject(clazz: Class[_]) = {
     val className = clazz.getName.split("\\.").last
     val firstMethod = clazz.getMethods.head//for simplicity
     val methodName = firstMethod.getName
     val parametersClasses = firstMethod.getParameterTypes.map(_.getName).toSeq

     val objectDefinition = "object " + className + " {\n" +
         generateMethodDefinition(className, methodName, parametersClasses) +
         "\n}"

     objectDefinition
 }

 def generateMethodDefinition(className: String, methodName: String, parameterClasses: Seq[String]) = {
     val newMethodName: String = "   def invoke" + methodName.capitalize + "On"

     val parameterList: String = "(o:" + className + ", " + parameterClasses.zipWithIndex.map {
         case (argClassName, index) => "arg" + index + ": " + argClassName
     }.mkString(", ") + ")"

     val generateOldMethodCall: String = "o." + methodName + parameterClasses.zipWithIndex.map {
         case (argClassName, index) => "arg" + index
     }.mkString("(", ",", ")")

     newMethodName + parameterList + " = " + generateOldMethodCall
 }

授業のために

class A {
   def foo(x: String, y: String) = x + y
}

生成されます

object A {
   def invokeFooOn(o:A, arg0: java.lang.String, arg1: java.lang.String) = o.foo(arg0,arg1)
}
于 2012-11-04T14:20:25.323 に答える