[英]How to return a function in scala
如何在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())
打印1 2 3 5 8
我无法弄清楚如何在Scala中编写相同的内容。
1.在Apocalisp评论后更正
稍微短一点,你不需要退货。
def fib() = {
var a = 0
var b = 1
() => {
val t = a;
a = b
b = t + b
b
}
}
尔加! 可变变量?!
val fib: Stream[Int] =
1 #:: 1 #:: (fib zip fib.tail map Function.tupled(_+_))
您可以返回获取第n个fib的文字函数,例如:
val fibAt: Int => Int = fib drop _ head
编辑:既然你要求“每次调用f时获得不同的值”的功能方式,这就是你如何做到这一点。 这使用Scalaz的State
monad:
import scalaz._
import Scalaz._
def uncons[A](s: Stream[A]) = (s.tail, s.head)
val f = state(uncons[Int])
值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
显然,你获得的价值取决于你拨打f
的次数。 但这完全是功能性的,因此模块化和可组合。 例如,我们可以传递任何非空的Stream,而不仅仅是fib
。
所以你看,你可以有没有副作用的效果。
虽然我们正在分享与该问题仅相关的斐波那契函数的酷实现,但这里是一个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)
}
它使用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
}
得到它了!! 经过一些试验和错误后:
def fib() : () => Int = {
var a = 0
var b = 1
return (()=>{
val t = a;
a = b
b = t + b
b
})
}
测试:
val f = fib()
println(f(),f(),f(),f())
1 2 3 5 8
使用元组时不需要temp var:
def fib() = {
var t = (1,-1)
() => {
t = (t._1 + t._2, t._1)
t._1
}
}
但在现实生活中你应该使用Apocalisp的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.