Extraction of a method into an independent function in Scala

Given something like:

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

How to (automatically) extract function (s):

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

With this exact type signature (first an object, then a list of parameters). Let me state the problem very clearly:

"Given the method f(x1: X1, ..., xn: Xn) defined in the context of class A , how to automatically extract the function f' so that (i) receives an instance A type A and (ii) a list of parameters corresponding to 1: 1, to the list of parameters f , namely: x1: X, ... xn: Xn , the implementation of which is exactly af(x1: X1, ..., xn: Xn) "

Or even:

Capturing the concept of lambda calculus extensiveness such that you automatically extract λx.(fx) from f whenever x not mapped to f .

This could be solved first by finding a way to access the identifiers f , g , ... without having a specific a: A (for example, it will have a specific A defined). We could just write f' or g' hand, but let spoil DRYness.


PS Perhaps this is impossible without reflection at run time (although this is possible with Scala 2.10+ macros), since I cannot find a way to refer to the identifiers f or g without a specific instance ( a: A ) in advance. But it would be something like the following, without having to resort to strings :

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

I also understand that the practical use of the question can help participants suggest alternatives, but I discuss this in an abstract sense. I am not trying to solve another problem that I led to this. I'm trying to find out if this one is possible :-) Here is a very good article to really understand the motivation behind this issue, with circulations over Eta-decompositions on Scala.

+6
source share
3 answers

Of course, you could do this at compile time using macros — I’m doing something very similar to the preliminary release of ScalaMock 3 — object mock instances of anonymous classes, where each member is implemented by an instance of the mock function. You may be able to use it as a starting point for what you are trying to do.

Warning : ScalaMock 3 only works with Scala 2.10.0-M6. It does not work with M7 or the current development version due to breaking changes to the macro API that I don’t have (yet!) To be able to access.

+2
source

This is similar to the Lensed project, which creates lenses for the Scala case classes. I believe that it would be possible to modify it to create methods that you describe instead of lenses.

0
source

I know this is not a very pretty solution, but if you cannot use macros, you can create the source code for a suitable companion object and compile it at a separate build stage.

 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 } 

for class

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

he will generate

 object A { def invokeFooOn(o:A, arg0: java.lang.String, arg1: java.lang.String) = o.foo(arg0,arg1) } 
-2
source

Source: https://habr.com/ru/post/927126/


All Articles