Подтвердить что ты не робот

Как вернуть функцию в scala

Как вернуть функцию боковое лексическое закрытие 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 комментарий

4b9b3361

Ответ 1

Немного короче, вам не нужно возвращать.

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

Ответ 2

Г! Переменные переменные?!

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.

Итак, вы видите, вы можете иметь эффекты без побочных эффектов.

Ответ 3

Пока мы используем интересные реализации функции фибоначчи, которые касаются только касательно вопроса, здесь 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
}

Ответ 4

Получил! после некоторых проб и ошибок:

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

Ответ 5

Вам не нужно использовать temp var при использовании кортежа:

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

Но в реальной жизни вы должны использовать решение Apocalisp.