17

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

Community
  • 1
  • 1
OscarRyz
  • 196,001
  • 113
  • 385
  • 569

5 Answers5

21

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
    }
}
fedesilva
  • 1,532
  • 13
  • 12
  • Thanks for posting this (just helped me). I want to add that if one desires to explicitly state the return type, one can add ": ReturnType" after the closing "}" (e.g. "} : Int" ). – Malcolm Feb 25 '14 at 22:32
20

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.

Apocalisp
  • 34,834
  • 8
  • 106
  • 155
  • 1
    +1 for the answer. The example is great, but, not really what I was looking for/asked. Thanks anyway. – OscarRyz Nov 24 '10 at 05:28
  • 10
    Well, you did ask for a function. A side-effenting lexical closure is emphatically not a function. – Apocalisp Nov 24 '10 at 05:43
  • I get an `error: type mismatch; found: Int; required: (Int, Int)` on Scala 2.8.1. What's wrong here? – soc Nov 24 '10 at 14:08
  • @Apocalisp I'd just enclose the whole expression inside parenthesis instead using dot notation. `(fib zip fib.tail map Function.tupled(_+_))`. More importantly, using `def` instead of `val` means this definition is not O(1). – Daniel C. Sobral Nov 24 '10 at 15:38
  • @OscarRyz: What do you mean by "different values after"? In what sense can a function return different values at different times, and what does "after" mean in that context? – Apocalisp Nov 24 '10 at 18:57
  • @Apocalisp: Oops! I can barely understand what I wrote, ehem. Here it goes again: Is there a *functional* way to have a *side-effecting lexical closure* returning different values after each invocation in Scala? For instance: `val f = fib(); f(); /*=1*/ f();/*=2*/f();/*=3*/...` Or is it something just not supported by the functional paradigm? – OscarRyz Nov 24 '10 at 19:09
  • @OscarRyz: Functional and side-effecting contradict each other. You have to make your state explicit. See the updated answer. – Apocalisp Nov 24 '10 at 19:56
  • @Apocalisp: Is there a way of doing `for { _ <- "n times f"; x <- f}` or similar in order to get the nth value? – Debilski Nov 24 '10 at 21:35
  • @Debiliski: `def times[S,A](n: Int, s: State[S, A]): State[S, A] = if (n < 1) s else for { _ <- s; x <- times(n - 1, s) } yield x` – Apocalisp Nov 24 '10 at 22:44
  • Can someone explain the difference between a side-effecting lexical closure and a function here? Google search on "side effecting lexical closure" is returning this question as the only seemingly relevant answer... – corazza Feb 16 '14 at 16:40
  • For those wondering, I've got the [answer](http://stackoverflow.com/a/22288476/924313). A "side effecting lexical closure" is just a closure (function with an execution environment) with side effects, and "lexical closure" seems to be a fancy term for closures... – corazza Mar 09 '14 at 21:51
  • 1
    this is more accurate answer for Scala way of doing things, this answer the one should be accepted – DevZer0 Oct 22 '16 at 06:00
8

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
}
Community
  • 1
  • 1
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
3

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
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
1

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.

Landei
  • 54,104
  • 13
  • 100
  • 195
  • +1 heheh well, in real life I wouldn't code fibonacci :) I agree Apocalisp solution is enlightening – OscarRyz Nov 24 '10 at 16:20