如何从Scala中的函数中将函数指定为返回类型

时间:2012-07-11 13:23:07

标签: function scala return-type

我对Scala很新,我遇到了一个问题。

我正在尝试编写一个包含函数队列的类。我希望能够将功能添加到队列中,并且在添加所有功能后,运行这些功能。基本上构建一个表达式:“function1(function2(function3()))”返回然后进行评估。这是我到目前为止的代码:

  class Pipeline() {

    // Queue of functions to run
    private var queue: Queue[ _ => _] = new LinkedList();

    // Add functions to the queue 
    def addFunction(func:_ => _ ): Unit ={
      queue.add(func)
    }

    // Run all the functions in the queue
    def run(): Unit = {
      val function = runHelper(queue.poll(), queue)
      function
    }

    def runHelper(func: _ => _, queue: Queue[_ => _]): _  = {
      // Recursion base case
      if(queue.isEmpty)
        return func
      // Keep building the function recursively
      else
        func(runHelper(queue.poll(), queue))        
    }    
  }

我确信这里有多个错误。但是现在,我坚持的是runHelper函数的返回类型。正如您所看到的,我正在尝试使用_通配符,但这会产生编译错误。我如何定义该函数将返回一个函数?我是否会以一种好的方式解决这个问题 - 如果没有,请指出我更适合解决问题的方向。

edit1:澄清 事先不知道函数的输入和返回类型,它们的序列需要能够动态分配。

编辑2:更多问题 我一直在努力让代码Edmondo1984建议以我想要的方式工作,但我似乎无法得到它。

我需要做的是这样的事情:

val func1: String => File = function1
val func2: File => File = function2

var queue = func1

if(runFunc2)
    queue = queue :: func2

queue("exampleString")

我特别需要知道的是如何能够执行“queue = queue :: func2”。因为::返回一个FunctionQueue,我想我可以将它分配给队列变量。但话说回来,我想,因为变量的第一次初始化导致它具有“String => File”需求。我觉得我在这里有点过头了,任何帮助都会非常感激。

5 个答案:

答案 0 :(得分:3)

我更喜欢的功能形式是:(parameter list) => returnType

我认为您的代码应该是这样的。我的IDE喜欢它,但这不能保证:

class Pipeline[T]() {

 // Queue of functions to run
 private var queue: util.Queue[ (T) => T] = new util.LinkedList()

 // Add functions to the queue
 def addFunction(func: (T)=> T ) {
   queue.add(func)
 }

 // Run all the functions in the queue
 def run() {
   val function = runHelper(queue.poll(), queue)
   function
 }

 def runHelper(func: (T) => T, queue: util.Queue[(T)=> T ]): (T)=>T = {
   // Recursion base case
   if(queue.isEmpty)
     func
   // Keep building the function recursively
   else
     func compose runHelper(queue.poll(), queue)
  }
}

答案 1 :(得分:3)

你可以尝试一下函数组合。比如这样。

val f = (x:Int) => 2 * x
val g = f.compose(f)

如果输入和输出类型不同,则必须注意输入和输出匹配...

答案 2 :(得分:3)

您尝试做的是不可能的,因为_是存在类型的占位符:存在但当前不相关的类型:例如,当您要打印如下列表时,可以使用它:< / p>

scala>  def aMethod(a:List[_]) = println(a.size)
aMethod: (a: List[_])Unit

scala>  val b = List(2,3,4)
b: List[Int] = List(2, 3, 4)

scala>  aMethod(b)
3

这是有效的,因为事实上你不能访问列表的元素,所以你可以想象你不需要他们的类。

因为Scala是一种强类型语言,即编译器检查代码中是否遵守了签名。队列[_ =&gt; _]是从未知类型到未知类型的函数队列,它没有用,因为如果您尝试弹出一个函数并将其应用于输入参数,您将无法验证是否输入参数匹配签名。

您尝试做的事情并非无足轻重,您需要以递归方式定义队列。您可能想要阅读无形HLIST实现,但想法如下:

trait FunctionQueue[A,B]{

  def ::[C](newFunction: C => A): FunctionQueue[C,B]

  def apply(a:A):B
}

class FunctionQueueImpl[A,B,C](val f:A=>B, val queue:FunctionQueue[B,C]) extends FunctionQueue[A,C]{

  def apply(a:A) = queue.apply(f(a))

  def ::[D](newFunction: (D) => A):FunctionQueue[D,C] = new FunctionQueueImpl[D,A,C](newFunction,this)
}

object FunctionQueue {
  def EmptyQueue[T]:FunctionQueue[T,T] = new FunctionQueue[T,T] {
    def ::[C](newFunction: (C) => T):FunctionQueue[C,T] = new FunctionQueueImpl[C,T,T](newFunction,this)

    def apply(a: T):T = a
  }

  implicit def functionToQueue[A,B](function:A => B):FunctionQueue[A,B] = new FunctionQueueImpl(function, EmptyQueue[B])
}

现在您可以在repl中尝试:

scala>  import FunctionQueue._
import FunctionQueue._

scala>  val a: Int => Int = _ * 10
a: Int => Int = <function1>


scala>  val b: Double => Int = _.toInt 
b: Double => Int = <function1>

scala>  val c : String => Double = _.toDouble
c: String => Double = <function1>

scala>  val queue = c::b::a
queue: FunctionQueue[String,Int] = FunctionQueueImpl@cccfa5e

scala>  queue("1.25")
res1: Int = 10

scala>  queue("3.25")
res2: Int = 30

我建议阅读Miles Sabins的工作以了解更多信息。

答案 3 :(得分:1)

关于实现,您可以使用简单的List函数T => T(称为内功能)。

现在,在scalaz中,您有一个Monoid(由SemigroupZero构建)的实例,用于此类函数。这意味着,您可以编写以下代码:

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> val f = ((_:Int) + 6).endo
f: scalaz.Endo[Int] = <function1>

scala> val g = ((_:Int) * 4).endo
g: scalaz.Endo[Int] = <function1>

scala> val h = (-(_:Int)).endo
h: scalaz.Endo[Int] = <function1>

scala> f :: g :: h :: nil
res3: List[scalaz.Endo[Int]] = List(<function1>, <function1>, <function1>)

scala> .asMA.sum
res4: scalaz.Endo[Int] = <function1>

scala> f(g(h(1)))
res5: Int = 2

scala> res4(1)
res6: Int = 2

答案 4 :(得分:0)

您可以指定函数的类型,如下所示:

Function[T, T]

T => T

假设你的函数的输入和输出都是相同的,它们应该是真的。当然,您必须指定或替换T

如果你真的有可变输入输出,那么整个方案将变得更加复杂。

相关问题