如何在scala中返回一个函数

Osc*_*Ryz 17 scala function return-value go

如何 在Scala中返回一个函数 副作用词法闭包 1

例如,我在Go中查看此代码示例:

...    
// fib returns a function that returns
// successive Fibonacci numbers.
func fib() func() int {
    a, b := 0, 1
    return func() int {
        a, b = b, a+b
        return b
    }
}
...
println(f(), f(), f(), f(), f())
Run Code Online (Sandbox Code Playgroud)

打印1 2 3 5 8

我无法弄清楚如何在Scala中编写相同的内容.

1.在Apocalisp评论后更正

fed*_*lva 21

稍微短一点,你不需要退货.

def fib() = {
    var a = 0
    var b = 1
    () => { 
        val t = a;
        a = b
        b = t + b
        b
    }
}
Run Code Online (Sandbox Code Playgroud)


Apo*_*isp 20

尔加!可变变量?!

val fib: Stream[Int] =
  1 #:: 1 #:: (fib zip fib.tail map Function.tupled(_+_))
Run Code Online (Sandbox Code Playgroud)

您可以返回获取第n个fib的文字函数,例如:

val fibAt: Int => Int = fib drop _ head
Run Code Online (Sandbox Code Playgroud)

编辑:既然你要求"每次调用f时获得不同的值"的功能方式,这就是你如何做到这一点.这使用Scalaz的Statemonad:

import scalaz._
import Scalaz._

def uncons[A](s: Stream[A]) = (s.tail, s.head)
val f = state(uncons[Int])
Run Code Online (Sandbox Code Playgroud)

该值f是状态转换函数.给定一个流,它将返回它的头部,并通过取尾来"改变"侧面的流.请注意,f完全没有注意到fib.这是一个REPL会话,说明了它的工作原理:

scala> (for { _ <- f; _ <- f; _ <- f; _ <- f; x <- f } yield x)
res29: scalaz.State[scala.collection.immutable.Stream[Int],Int] = scalaz.States$$anon$1@d53513

scala> (for { _ <- f; _ <- f; _ <- f; x <- f } yield x)
res30: scalaz.State[scala.collection.immutable.Stream[Int],Int]  = scalaz.States$$anon$1@1ad0ff8

scala> res29 ! fib
res31: Int = 5

scala> res30 ! fib
res32: Int = 3
Run Code Online (Sandbox Code Playgroud)

显然,你获得的价值取决于你打电话的次数f.但这完全是功能性的,因此模块化和可组合.例如,我们可以传递任何非空的Stream,而不仅仅是fib.

所以你看,你可以有没有副作用的效果.

  • 好吧,你确实要求一个功能.一个侧面有效的词汇封闭显然不是一个功能. (10认同)

Aar*_*rup 8

虽然我们正在分享与该问题仅相关的斐波那契函数的酷实现,但这里是一个memoized版本:

val fib: Int => BigInt = {                         
   def fibRec(f: Int => BigInt)(n: Int): BigInt = {
      if (n == 0) 1 
      else if (n == 1) 1 
      else (f(n-1) + f(n-2))                           
   }                                                     
   Memoize.Y(fibRec)
}
Run Code Online (Sandbox Code Playgroud)

它使用memoizing定点组合器作为这个问题的答案:在Scala 2.8中,用什么类型来存储内存中的可变数据表?

顺便提一下,组合子的实现提出了一种稍微更明确的技术来实现你的函数副作用词法闭包:

def fib(): () => Int = {
   var a = 0
   var b = 1
   def f(): Int = {
      val t = a;
      a = b
      b = t + b
      b
  }
  f
}
Run Code Online (Sandbox Code Playgroud)