Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a function in scala

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

like image 817
OscarRyz Avatar asked Nov 23 '10 23:11

OscarRyz


People also ask

Can you use return in Scala?

The Scala programming language, much like Java, has the return keyword, but its use is highly discouraged as it can easily change the meaning of a program and make code hard to reason about.


2 Answers

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
    }
}
like image 160
fedesilva Avatar answered Oct 13 '22 19:10

fedesilva


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.

like image 45
Apocalisp Avatar answered Oct 13 '22 17:10

Apocalisp