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

Возможны рекурсивные лямбда-выражения?

Я пытаюсь написать лямбда-выражение, которое вызывает себя, но я не могу найти синтаксиса для этого или даже если это возможно.

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

def add(a, b):
   if a <= 0:
      return b
   else:
      return 1 + add(a - 1, b)

add = lambda a, b: [1 + add(a-1, b), b][a <= 0]

но вызов лямбда-формы для добавления результатов в ошибку времени выполнения, поскольку достигается максимальная глубина рекурсии. Возможно ли это сделать в python? Или я просто делаю какую-то глупую ошибку? О, я использую python3.0, но я не думаю, что это важно?

4b9b3361

Ответ 1

Возможно, вам нужен Y combinator?

Изменить - сделайте это комбинатор Z (я не понял, что комбинаторы Y больше для вызова по имени)

Использование определения комбинатора Z из Wikipedia

>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))

Используя это, вы можете затем определить добавление как полностью анонимную функцию (т.е. ссылку на ее имя в определении)

>>> add = Z(lambda f: lambda a, b: b if a <= 0 else 1 + f(a - 1, b))
>>> add(1, 1)
2
>>> add(1, 5)
6

Ответ 2

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

Следовательно, использование выражения лямбда бесполезно и будет только путать людей. Поэтому создайте его с помощью def.

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

add = lambda a, b: a > 0 and (1 + add(a-1, b)) or b

Что заботится об этой проблеме. Тем не менее, ваш первый def - правильный способ сделать это.

Ответ 3

Возможно, вы должны попробовать Z combinator, где этот пример:

>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))
>>> fact = lambda f: lambda x: 1 if x == 0 else x * f(x-1)
>>> Z(fact)(5)
120

Ответ 4

add = lambda a, b: b if a <= 0 else 1 + add(a - 1, b)

Ответ 5

Вы хотите Y combinator или какой-нибудь другой комбинатор фиксированных точек.

Здесь пример реализации как выражение лямбда Python:

Y = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))

Используйте его так:

factorial = Y(lambda f: (lambda num: num and num * f(num - 1) or 1))

То есть вы переходите в Y() функцию с одним аргументом (или лямбдой), которая в качестве аргумента получает рекурсивную версию. Таким образом, функция не должна знать свое собственное имя, поскольку оно получает ссылку на себя вместо этого.

Обратите внимание, что это делает сложным для вашей функции add(), потому что Y combinator поддерживает только передачу одного аргумента. Вы можете получить больше аргументов currying - но я оставлю это как упражнение для читателя.: -)

Ответ 6

немного поздно... но я только что нашел этот жемчуг @http://metapython.blogspot.com/2010/11/recursive-lambda-functions.html

def myself (*args, **kw):
    caller_frame = currentframe(1)
    code = caller_frame.f_code
    return  FunctionType(code, caller_frame.f_globals)(*args,**kw)

print "5! = "
print (lambda x:1 if n <= 1 else myself(n-1)*n)(5)