如何在scala中返回一个函数

发布于 2024-10-04 14:33:58 字数 761 浏览 7 评论 0原文

如何返回 function 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评论后更正

How can I return a function side-effecting lexical closure1 in Scala?

For instance, I was looking at this code sample in 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())

prints
1 2 3 5 8

And I can't figure out how to write the same in Scala.

1. Corrected after Apocalisp comment

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

久随 2024-10-11 14:33:58

稍微短一点,不需要退货。

def fib() = {
    var a = 0
    var b = 1
    () => { 
        val t = a;
        a = b
        b = t + b
        b
    }
}

Slightly shorter, you don't need the return.

def fib() = {
    var a = 0
    var b = 1
    () => { 
        val t = a;
        a = b
        b = t + b
        b
    }
}
野心澎湃 2024-10-11 14:33:58

嘎!可变变量?!

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

所以你看,你可以产生效果而没有副作用。

Gah! Mutable variables?!

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

You can return a literal function that gets the nth fib, for example:

val fibAt: Int => Int = fib drop _ head

EDIT: Since you asked for the functional way of "getting a different value each time you call f", here's how you would do that. This uses Scalaz's State monad:

import scalaz._
import Scalaz._

def uncons[A](s: Stream[A]) = (s.tail, s.head)
val f = state(uncons[Int])

The value f is a state transition function. Given a stream, it will return its head, and "mutate" the stream on the side by taking its tail. Note that f is totally oblivious to fib. Here's a REPL session illustrating how this works:

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

Clearly, the value you get out depends on the number of times you call f. But this is all purely functional and therefore modular and composable. For example, we can pass any nonempty Stream, not just fib.

So you see, you can have effects without side-effects.

宛菡 2024-10-11 14:33:58

虽然我们正在分享与问题无关的斐波那契函数的酷实现,但这里有一个记忆版本:

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)
}

它使用实现的记忆定点组合器作为此问题的答案:在 Scala 2.8 中,使用什么类型存储内存中的可变数据表?

顺便说一句,组合器的实现建议使用一种稍微更明确的技术来实现 function 副作用词法闭包:

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

While we're sharing cool implementations of the fibonacci function that are only tangentially related to the question, here's a memoized version:

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)
}

It uses the memoizing fixed-point combinator implemented as an answer to this question: In Scala 2.8, what type to use to store an in-memory mutable data table?

Incidentally, the implementation of the combinator suggests a slightly more explicit technique for implementing your function side-effecting lexical closure:

def fib(): () => Int = {
   var a = 0
   var b = 1
   def f(): Int = {
      val t = a;
      a = b
      b = t + b
      b
  }
  f
}
不语却知心 2024-10-11 14:33:58

知道了!!经过一番尝试和错误:

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

Got it!! after some trial and error:

def fib() : () => Int = {
    var a = 0
    var b = 1
    return (()=>{ 
        val t = a;
        a = b
        b = t + b
        b
    })
}

Testing:

val f = fib()
println(f(),f(),f(),f())

1 2 3 5 8
平安喜乐 2024-10-11 14:33:58

使用元组时不需要临时变量:

def fib() = {
  var t = (1,-1)
  () => { 
    t = (t._1 + t._2, t._1)
    t._1
  }
}

但在现实生活中,您应该使用 Apocalisp 的解决方案。

You don't need a temp var when using a tuple:

def fib() = {
  var t = (1,-1)
  () => { 
    t = (t._1 + t._2, t._1)
    t._1
  }
}

But in real life you should use Apocalisp's solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文