0

In Scala, the for...yield statement works great for chaining together a series of function calls to define a graph of transformations using monad practices. However, I would like to define the function calls outside of the function scope, and pass them in dynamically so that the chained function calls can be defined by another application and passed in as an argument using a string.

According to the scala language spec the data type used by the for...yield is an enumeration, but I can only find hard-coded examples of enumerations.

Is there a way to generate an enumeration dynamically and pass it into the for...yield statement?

For example, given this working code:

import scala.util.Try

val map1: Map[String, Int] = Map("val1"->1,"val2"->2,"val3"->3)

def mapTest(inputMap: Map[String, Int]) = {
    for {
        x <- Try(inputMap.mapValues(_ * 2))
        y <- Try(x.mapValues(_ * 2))
        z <- Try(y.mapValues(_ *2))
    } yield z
}

mapTest(map1).get

Run it as something like this where the list of functions is passed in as functionList (psuedo-code):

import scala.util.Try

val map1: Map[String, Int] = Map("val1"->1,"val2"->2,"val3"->3)
val functionList: String = "(x <- Try(inputMap.mapValues(_ * 2))),(y <- Try(x.mapValues(_ * 2))),(z <- Try(y.mapValues(_ *2)))"

def mapTest(inputMap: Map[String, Int], functionList: String) = {
    for {functionList.toEnum} yield z
}

mapTest(map1).get

Edit: It looks like the only way to pass functions in as a string is using run-time compilation like this example: How to convert a string from a text input into a function in a Scala

And more examples here: https://docs.scala-lang.org/overviews/repl/embedding.html

It's a different problem than running a list of functions. I need a way to convert a string containing a list of functions into actual functions.

Basically would need to pass in something like this string into the runtime compiler code, and then run mapTest(inputMap) which returns the new map z.

val functionString = s"""
 def mapTest(inputMap: Map[String, Int]) = {
|    for {
|        x <- Try(inputMap.mapValues(_ * 2))
|        y <- Try(x.mapValues(_ * 2))
|        z <- Try(y.mapValues(_ *2))
|    } yield z
|}""".stripMargin
jljohn00
  • 41
  • 3
  • 1
    Please provide a link to the documentation that associates a for-comprehension with an enumeration type. The `for`...`yield` is actually syntactic sugar for a `map()` and `flatMap()` chain. No `Enum` involved. – jwvh Jan 11 '20 at 06:57
  • It's all here: https://scala-lang.org/files/archive/spec/2.11/06-expressions.html#for-comprehensions-and-for-loops It expands to a flatMap as shown in the example "A for comprehension" but I can't figure out how to represent the series of "p <-e" statements as a string and convert it to an enum: "for ( <- ; ′ <- ′;…) yield ″ – jljohn00 Jan 11 '20 at 07:16
  • 1
    Ah, I see your confusion. The term `Enumerators` is a language specification. There is no `Enumerators` type in the Standard Library, just as there is no `Expr1` type or `Generator` type. Those are terms used to build the language description. – jwvh Jan 11 '20 at 07:32
  • Got it, so there isn't a way to pass in the generator expressions dynamically to the inner part of the for...yield? Sounds like the solution would be closer to this code generator example? https://medium.com/@kadirmalak/compile-arbitrary-scala-code-at-runtime-using-reflection-with-variable-injection-2002e0500565 – jljohn00 Jan 11 '20 at 08:48
  • Does this answer your question? [Scala apply list of functions to a object](https://stackoverflow.com/questions/42039355/scala-apply-list-of-functions-to-a-object) – Tim Jan 11 '20 at 09:14
  • Unfortunately, no. In my use case the functions would be passed into the main method args of a spark job via a string that comes from another application, and the number of function calls contained within the string is not known ahead of time. – jljohn00 Jan 11 '20 at 16:06

1 Answers1

0

It looks like the only way to pass functions in as a string is using run-time compilation like this example: How to convert a string from a text input into a function in a Scala

And more examples here: https://docs.scala-lang.org/overviews/repl/embedding.html

jljohn00
  • 41
  • 3