Ответ 1
Немного короче, вам не нужно возвращать.
def fib() = {
var a = 0
var b = 1
() => {
val t = a;
a = b
b = t + b
b
}
}
Как вернуть функцию боковое лексическое закрытие 1 в Scala?
Например, я смотрел этот пример кода в 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-й фид, например:
val fibAt: Int => Int = fib drop _ head
EDIT: Поскольку вы попросили функциональный способ "получать различное значение каждый раз, когда вы вызываете 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] = [email protected]
scala> (for { _ <- f; _ <- f; _ <- f; x <- f } yield x)
res30: scalaz.State[scala.collection.immutable.Stream[Int],Int] = [email protected]
scala> res29 ! fib
res31: Int = 5
scala> res30 ! fib
res32: Int = 3
Очевидно, что значение, которое вы выбрали, зависит от количества раз, когда вы вызываете f
. Но все это чисто функционально, а потому модульно и сложно. Например, мы можем передать любой непустой поток, а не только fib
.
Итак, вы видите, вы можете иметь эффекты без побочных эффектов.
Пока мы используем интересные реализации функции фибоначчи, которые касаются только касательно вопроса, здесь 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)
}
В нем используется 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.