Ниже я преобразовал программу, чтобы использовать продолжение (then
) и батут (run
/ recur
). Он развивает линейный итеративный процесс и не будет переполнять стек. Если вы не сталкиваетесь с проблемой переполнения стека, это мало поможет вашей конкретной проблеме, но может научить вас, как сгладить вычисления ветвления.
Этот процесс преобразования нормальной функции в стиль передачи продолжения может быть механическим. Если вы немного прищурите глаза, вы увидите, что в программе есть почти такие же элементы, как у вас. Встроенные комментарии показывают код рядом друг с другом -
import numpy as np
def identity (x):
return x
def recur (*values):
return (recur, values)
def run (f):
acc = f ()
while type (acc) is tuple and acc [0] is recur:
acc = f (*acc [1])
return acc
def myfunc (a):
# def recursive(w,i,j)
def loop (w = a, i = 0, j = len(a)-1, then = identity):
if i == j: # same
return then (w[i]) # wrap in `then`
else: # same
k = (j - i) // 2 + i # same
return recur \ # left=recursive(w,i,k)
( w
, i
, k
, lambda left:
recur # right=recursive(w,k+1,j)
( w
, k + 1
, j
, lambda right:
then # wrap in `then`
(f (left, right)) # same
)
)
return run (loop)
def f (a, b):
return a + b # same
a = np.random.rand(10) # same
print(a, myfunc(a)) # recursive(a, 0, a.shape[0]-1)
# [0.5732646 0.88264091 0.37519826 0.3530782 0.83281033 0.50063843 0.59621896 0.50165139 0.05551734 0.53719382]
# 5.208212213881435
Рекомендация Apple (c), но мне нравится звук (b). Статическая структура данных позволяет Вам скрывать детали GC от пользователя API при предотвращении опускающийся на уровень CFRetain/CFRelease. Как Вы заявляете, это также делает отладку и поблочное тестирование легче; если на объект все еще ссылается статическая структура данных после того, как это закончило свою задачу, Вы знаете, что существует ошибка.
Для a), более идиоматической альтернативы CFRetain(foo)
/CFRelease(foo)
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:foo]
/[[NSGarbageCollector defaultCollector] enableCollectorForPointer:foo]
.