Algorithm 置换函数调用

Algorithm 置换函数调用,algorithm,scala,code-generation,Algorithm,Scala,Code Generation,我想在数据集上运行一系列转换。这些转换的输入和输出在类型上总是相同的,所以我可以任意选择顺序。最后,我想评估不同订单的执行情况(输出数据的质量、计算性能等等)。因此,我给程序一个文件,其中每一行都包含一个函数标识符,并按如下方式运行: // read lines of file into plan for (x <- plan) { val temp : myDataType x match { case "Func_A" => temp = myData.map

我想在数据集上运行一系列转换。这些转换的输入和输出在类型上总是相同的,所以我可以任意选择顺序。最后,我想评估不同订单的执行情况(输出数据的质量、计算性能等等)。因此,我给程序一个文件,其中每一行都包含一个函数标识符,并按如下方式运行:

// read lines of file into plan
for (x <- plan) {

  val temp : myDataType

  x match {
    case "Func_A" => temp = myData.map(y => funcA(y))
    case "Func_B" => temp = myData.map(y => funcB(y))
    ...
  }

  myData = temp
}
def fromName(name: String): Int => Int = name match {
    case "f1" => f1
    case "f2" => f2
    case "f3" => f3
    case _ => throw new IllegalArgumentException("booooom!")
}
然而,在这种情况下,我需要提前知道所有(至少是我想尝试的)排列,并且会有很多(20+函数)。我还研究了编译时/运行时代码生成,但在我看来,这有点像杀伤力过大


所以,也许你有一些想法,如何更优雅地解决这个问题。

我认为这里需要解决两件事

  • 将函数链接在一起
  • 获取函数序列
  • 注意:为简单起见,我假设在
    Int
    上操作,因此函数类型为
    Int=>Int
    。您说过您正在映射到同一类型

    1.锁链 假设您有一系列函数和一些数据,可以执行以下操作:

    ...
    val plan: Seq[Int => Int] = ... // see my second point
    ...
    val myData = List(1, 2, 3, 4) // immutable List
    
    // Can use compose instead of andThen
    val compositeFunc = plan.foldLeft((i: Int) => i)(_ andThen _)
    val newData = myData map compositeFunc
    
    注意:您可以使用
    组合函数,然后使用
    组合
    ()

    2.获取函数序列(计划) 您可以通过多种方式执行此操作:

    • 在代码的某个映射中定义它们
    • 在代码中定义它们,并使用反射选择它们
    • 在运行时编译它们
    地图中的静态定义

    class MyFunctions {
      def f1(i: Int): Int = i * 2
      def f2(i: Int): Int = i * i
      def f3(i: Int): Int = i * i * i
    
      // Hardcoded map from string to function name
      // Avoids any reflection
      val funMap = Map[String, (Int) => Int](
        "f1" -> f1,
        "f2" -> f2,
        "f3" -> f3
      )
    }
    
    val funcs = new MyFunctions
    
    val myData = List(1, 2, 3, 4) // immutable List
    
    // Assume you read these from your file
    val planFromFile = List("f1", "f3", "f2") // String function names
    
    // Get functions using the hardcoded map
    val plan = planFromFile map (name => funcs.funMap(name))
    
    // Can use compose instead of andThen
    val compositeFunc = plan.foldLeft((i: Int) => i)(_ andThen _)
    
    // Map the function composition to your data
    val newData = myData map compositeFunc
    
    使用反射

    import scala.reflect.runtime.{universe => ru}
    
    class MyFunctions {
      def f1(i: Int): Int = i * 2
      def f2(i: Int): Int = i * i
      def f3(i: Int): Int = i * i * i
    }
    
    val funcs = new MyFunctions
    
    val myData = List(1, 2, 3, 4) // immutable List
    
    // Assume you read these from your file
    val planFromFile = List("f1", "f3", "f2") // String function names
    
    // Acts as a function wrapper that wraps a MethodMirror
    // Note that all functions in Scala are objects ((Int => Int) is shorthand for Function1 ...)
    class WrappedFunction(mirror: reflect.runtime.universe.MethodMirror) extends (Int => Int) {
      override def apply(v1: Int): Int = mirror(v1).asInstanceOf[Int]
    }
    
    // Returns function wrappers for each string
    // Note for simplicity there is no code dealing with missing function , errors etc.
    def getFunctions(names: Seq[String]): Seq[Int => Int] =
      names.map(s => new WrappedFunction(ru.runtimeMirror(funcs.getClass.getClassLoader)
        .reflect(funcs)
        .reflectMethod(ru.typeOf[MyFunctions]
          .decl(ru.TermName(s)).asMethod)))
    
    
    val reflectedFunctions = getFunctions(planFromFile)
    
    // Compose them from the generated functions
    val compositeFunc2 = reflectedFunctions.foldLeft((i: Int) => i)(_ andThen _)
    
    // Generate data
    val newData2 = myData map compositeFunc2
    
    我没有谈到在运行时编译,我假设这不是您的用例

    您还可以组合这些方法并使用反射生成贴图

    编辑显然,您也可以使用模式匹配来代替该映射。。大概是这样的:

    // read lines of file into plan
    for (x <- plan) {
    
      val temp : myDataType
    
      x match {
        case "Func_A" => temp = myData.map(y => funcA(y))
        case "Func_B" => temp = myData.map(y => funcB(y))
        ...
      }
    
      myData = temp
    }
    
    def fromName(name: String): Int => Int = name match {
        case "f1" => f1
        case "f2" => f2
        case "f3" => f3
        case _ => throw new IllegalArgumentException("booooom!")
    }
    

    有关反射的更多信息,请参阅文档:

    我认为这里需要解决两件事

  • 将函数链接在一起
  • 获取函数序列
  • 注意:为简单起见,我假设在
    Int
    上操作,因此函数类型为
    Int=>Int
    。您说过您正在映射到同一类型

    1.锁链 假设您有一系列函数和一些数据,可以执行以下操作:

    ...
    val plan: Seq[Int => Int] = ... // see my second point
    ...
    val myData = List(1, 2, 3, 4) // immutable List
    
    // Can use compose instead of andThen
    val compositeFunc = plan.foldLeft((i: Int) => i)(_ andThen _)
    val newData = myData map compositeFunc
    
    注意:您可以使用
    组合函数,然后使用
    组合
    ()

    2.获取函数序列(计划) 您可以通过多种方式执行此操作:

    • 在代码的某个映射中定义它们
    • 在代码中定义它们,并使用反射选择它们
    • 在运行时编译它们
    地图中的静态定义

    class MyFunctions {
      def f1(i: Int): Int = i * 2
      def f2(i: Int): Int = i * i
      def f3(i: Int): Int = i * i * i
    
      // Hardcoded map from string to function name
      // Avoids any reflection
      val funMap = Map[String, (Int) => Int](
        "f1" -> f1,
        "f2" -> f2,
        "f3" -> f3
      )
    }
    
    val funcs = new MyFunctions
    
    val myData = List(1, 2, 3, 4) // immutable List
    
    // Assume you read these from your file
    val planFromFile = List("f1", "f3", "f2") // String function names
    
    // Get functions using the hardcoded map
    val plan = planFromFile map (name => funcs.funMap(name))
    
    // Can use compose instead of andThen
    val compositeFunc = plan.foldLeft((i: Int) => i)(_ andThen _)
    
    // Map the function composition to your data
    val newData = myData map compositeFunc
    
    使用反射

    import scala.reflect.runtime.{universe => ru}
    
    class MyFunctions {
      def f1(i: Int): Int = i * 2
      def f2(i: Int): Int = i * i
      def f3(i: Int): Int = i * i * i
    }
    
    val funcs = new MyFunctions
    
    val myData = List(1, 2, 3, 4) // immutable List
    
    // Assume you read these from your file
    val planFromFile = List("f1", "f3", "f2") // String function names
    
    // Acts as a function wrapper that wraps a MethodMirror
    // Note that all functions in Scala are objects ((Int => Int) is shorthand for Function1 ...)
    class WrappedFunction(mirror: reflect.runtime.universe.MethodMirror) extends (Int => Int) {
      override def apply(v1: Int): Int = mirror(v1).asInstanceOf[Int]
    }
    
    // Returns function wrappers for each string
    // Note for simplicity there is no code dealing with missing function , errors etc.
    def getFunctions(names: Seq[String]): Seq[Int => Int] =
      names.map(s => new WrappedFunction(ru.runtimeMirror(funcs.getClass.getClassLoader)
        .reflect(funcs)
        .reflectMethod(ru.typeOf[MyFunctions]
          .decl(ru.TermName(s)).asMethod)))
    
    
    val reflectedFunctions = getFunctions(planFromFile)
    
    // Compose them from the generated functions
    val compositeFunc2 = reflectedFunctions.foldLeft((i: Int) => i)(_ andThen _)
    
    // Generate data
    val newData2 = myData map compositeFunc2
    
    我没有谈到在运行时编译,我假设这不是您的用例

    您还可以组合这些方法并使用反射生成贴图

    编辑显然,您也可以使用模式匹配来代替该映射。。大概是这样的:

    // read lines of file into plan
    for (x <- plan) {
    
      val temp : myDataType
    
      x match {
        case "Func_A" => temp = myData.map(y => funcA(y))
        case "Func_B" => temp = myData.map(y => funcB(y))
        ...
      }
    
      myData = temp
    }
    
    def fromName(name: String): Int => Int = name match {
        case "f1" => f1
        case "f2" => f2
        case "f3" => f3
        case _ => throw new IllegalArgumentException("booooom!")
    }
    

    有关反射的更多信息,请参见文档:

    因为您在这里使用的是
    map
    ,这告诉我您的
    funcA()
    等。独立地处理每个数据项,这意味着您不必多次调用
    map
    ,只需调用一次,就可以向它传递一个应用所有20个转换的函数。我没有Scala,但在Haskell中,您可以构建应用其他函数的函数;我相信在Scala中也有办法做到这一点。你是对的,但是将所有转换放在一个
    map
    中并不能回答我的问题,它只是将问题推到了其他地方。只需编写一个函数,从输入中读取函数列表,然后返回一个函数(我假设Scala有一流的函数?)将它们按顺序应用于给定的输入值。然后,您可以只运行一次
    map
    ,并将您刚刚构建的“无所不能”函数传递给它。我会尝试一下。因为您在这里使用的是
    map
    ,这告诉我您的
    funcA()
    等独立地处理每个数据项,这意味着您不必多次调用
    map
    ,只需调用它一次,就可以向它传递一个应用所有20个转换的函数。我没有Scala,但在Haskell中,您可以构建应用其他函数的函数;我相信在Scala中也有办法做到这一点。你是对的,但是将所有转换放在一个
    map
    中并不能回答我的问题,它只是将问题推到了其他地方。只需编写一个函数,从输入中读取函数列表,然后返回一个函数(我假设Scala有一流的函数?)将它们按顺序应用于给定的输入值。然后,您可以只运行一次
    map
    ,并将您刚刚构建的“无所不能”函数传递给它。我会试试的。太棒了。太棒了。