@@ -47,6 +47,91 @@ from the caller function (in this case also `factorial`). This means that the
47
47
resources in the caller function's scope are free to be garbage collected and that its
48
48
frame is popped from the call stack before we push the returned function on.
49
49
50
+ ## Nested Calls
51
+
52
+ In the previous example the whole concept of an accumulator my not fit your mental model
53
+ that well (it doesn't for me at least).
54
+ Luckily calls to ` tail_call ` support nested calls (i.e. another ` tail_call ` passed as an
55
+ argument).
56
+ Taking this functionality into consideration we can refactor the previous example.
57
+
58
+ ``` python
59
+ ...
60
+
61
+ @tail_recursive
62
+ def mul (a , b ):
63
+ return a * b
64
+
65
+ @tail_recursive
66
+ def factorial (n ):
67
+ if n == 1 :
68
+ return n
69
+ return mul.tail_call(n, factorial.tail_call(n - 1 ))
70
+
71
+ ...
72
+ ```
73
+
74
+ This, however, comes a performance cost and can be disabled as follows.
75
+
76
+ ``` python
77
+ @tail_recursive (nested_call_mode = " do_not_resolve_nested_calls" )
78
+ def factorial (n , accumulator = 1 ):
79
+ if n == 1 :
80
+ return accumulator
81
+ return factorial.tail_call(n - 1 , n * accumulator)
82
+ ```
83
+
84
+ or
85
+
86
+ ``` python
87
+ from tail_recursive import tail_recursive, NestedCallMode
88
+
89
+ ...
90
+
91
+ @tail_recursive (nested_call_mode = NestedCallMode.DO_NOT_RESOLVE_NESTED_CALLS )
92
+ def factorial (n , accumulator = 1 ):
93
+ ...
94
+ ```
95
+
96
+ Similarly, use ` nested_call_mode="resolve_nested_calls" ` or ` nested_call_mode=NestedCallMode.RESOLVE_NESTED_CALLS `
97
+ to explicitly enable this feature.
98
+
99
+ ## Current Limitations
100
+
101
+ ### Return Values
102
+
103
+ Currently tail calls that are returned as an item in a tuple or other
104
+ data structure are not evaluated.
105
+
106
+ The following will not evaluate the tail call.
107
+
108
+ ``` python
109
+ from tail_recursive import tail_recursive
110
+
111
+ @tail_recursive
112
+ def func (...):
113
+ ...
114
+ return return_val1, func.tail_call(... )
115
+ ```
116
+
117
+ A workaround is to use factory functions.
118
+
119
+ ``` python
120
+ from tail_recursive import tail_recursive
121
+
122
+ @tail_recursive
123
+ def tuple_factory (* args ):
124
+ return tuple (args)
125
+
126
+ @tail_recursive
127
+ def func (...):
128
+ ...
129
+ return tuple_factory.tail_call(
130
+ return_val1,
131
+ func.tail_call(... )
132
+ )
133
+ ```
134
+
50
135
## Other Packages
51
136
52
137
Check out [ tco] ( https://github.com/baruchel/tco ) for an alternative api with extra functionality.
0 commit comments