Как в языке Go создать рекурсивный функциональный литерал?

Как я понимаю, вы работали над упражнением в A Tour of Go, в котором необходимо было создать замыкание для итеративного возвращения чисел Фибоначчи. Вы уже нашли одно решение, но хотите узнать, есть ли другие способы реализации с учетом возможностей языка. Можете ли вы уточнить, правильно ли я понимаю, что ваш вариант с функцией g() является типичным примером рекурсивного функционального литерала? Также интересует вопрос о том, как можно применить синтаксис вызова сразу после определения функции. 

Как сделать рекурсию с использованием этого типа вызова? 

Вот мой текущий вариант кода: 

```go
package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	count := 0
	var g func(int) int
	g = func(n int) int {
		if n == 0 {
			return 0
		} else if n == 1 {
			return 1
		} else {
			return g(n-1) + g(n-2)
		}
	}

	return func() int {
		tmp := count
		count++
		return g(tmp)
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
```

Можно ли переписать этот вариант так, чтобы использовать синтаксис вызова с круглымі скобками в конце? Или в таком случае рекурсии не получится достичь? Спасибо.
  • 22 января 2025 г. 10:24
Ответы на вопрос 2
В языке Go вы можете создать рекурсивный функциональный литерал, используя локальные функции для поддержания состояния и обеспечения возможности рекурсивных вызовов. В вашем текущем коде уже реализована рекурсия через локальную переменную `g`, которая ссылается сама на себя.

Что касается синтаксиса вызова функции сразу после её определения, вы можете использовать анонимную функцию, которая будет моментально вызвана. Однако следует учесть, что для рекурсии вам всё ещё понадобится сохранить ссылку на функцию, чтобы она могла вызывать саму себя.

Вот пример кода с использованием анонимной функции и синтаксиса вызова:

```go
package main

import "fmt"

func fibonacci() func() int {
	count := 0

	var g func(int) int
	g = func(n int) int {
		if n == 0 {
			return 0
		} else if n == 1 {
			return 1
		} else {
			return g(n-1) + g(n-2)
		}
	}

	return func() int {
		defer func() { count++ }() // Увеличиваем count после вызова
		return g(count)
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
```

В этом коде мы сохраняем оригинальную логику. Однако, если вы хотите использовать анонимную функции с моментальным вызовом, вам нужно реализовать решение немного иначе. Но учтите, что для рекурсивных вызовов это может быть не самым очевидным и компактным решением.

Вот как это может выглядеть:

```go
package main

import "fmt"

func fibonacci() func() int {
	count := 0

	return func() int {
		return func(n int) int {
			if n == 0 {
				return 0
			} else if n == 1 {
				return 1
			} else {
				return innerFib(n-1) + innerFib(n-2)
			}
		}(count)
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
```

В этом случае мы определяем анонимную функцию внутри возвращаемой функции, которая получает `count` в качестве аргумента. Таким образом, мы оставляем возможность рекурсивного вызова, но синтаксис немного отличается от оригинального кода. Тем не менее, это уменьшает гибкость, связав вызов с одной переменной. 

Итак, чтобы ответить на ваш вопрос: использовать мгновенный вызов с рекурсией возможно, но потребуется немного изменить подход, чтобы сохранить необходимую ссылку на рекурсивную функцию.
Перемудрили что-то. Кроме того если нужно именно рекурсивно, нужно добавить мемоизацию, если хотите чтобы оно вычислялось за конечное время (запустите ваш код для тысячи) 

А вообще в задании ничего про рекурсию не сказано, думаю тур предполагает, что вы напишите что-то такое
func fibonacci() func() int {
    a, b := 0, 1
    return func() int {
        result := a
        a, b = b, a+b
        return result
    }
}
Похожие вопросы