簡體   English   中英

如何從Scala中的函數中將函數指定為返回類型

[英]How to assign a function as a return type from function in Scala

我對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”需求。 我覺得我在這里有點過頭了,任何幫助都會非常感激。

我更喜歡函數的形式是:( (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)
  }
}

你可以嘗試一下函數組合。 比如這樣。

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

如果輸入和輸出類型不同,你必須注意輸入和輸出匹配...

您嘗試做的是不可能的,因為_是存在類型的占位符:存在但當前不相關的類型:例如,當您要打印如下列表時,可以使用它:

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是一種強類型語言,即編譯器檢查代碼中是否遵守了簽名。 隊列[_ => _]是從未知類型到未知類型的函數隊列,它沒有用,因為如果您嘗試彈出一個函數並將其應用於輸入參數,您將無法驗證輸入參數是否與簽名匹配。

您要做的事情並非無足輕重,您需要以遞歸方式定義隊列。 您可能希望閱讀Shapeless 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的工作以了解更多。

關於實現,您可以使用一個簡單的函數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

您可以指定函數的類型,如下所示:

Function[T, T]

要么

T => T

假設你的函數的輸入和輸出都是相同的,它們應該是真的。 您當然必須指定或替換T

如果你真的有可變輸入輸出,整個方案將變得更加復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM