我对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”需求。我觉得我在这里有点过头了,任何帮助都会非常感激。
答案 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
(由Semigroup
和Zero
构建)的实例,用于此类函数。这意味着,您可以编写以下代码:
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
。
如果你真的有可变输入输出,那么整个方案将变得更加复杂。