-
-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Remove recursive interleave
calls
#59
Comments
It appears that |
Yes, that's the same type of thing I did in |
I'm not able to reproduce the error locally. |
Ah. I tried in a fresh environment and the error still shows on my machine. |
FYI: If I set
|
RecursionError
on simple exampleinterleave
interleave
interleave
calls
I may be way out my league here, but this could not be done with zip and enumerate? I've included a small snippet to illustrate what I mean.
If this is a complete misunderstanding, just let me know; I do not mean to interrupt or obstruct. Edit: a little more experimenting below -->
This appears to work even with larger lists, I tested 50_000 and 500_000, both successful. |
Now that I'm coming back to this, I don't think the problem is in |
I can see that I am in fact out of my league here then, cheers and good luck! |
There's a bit of context here that may make things seem foreign, but we're really just talking about generators calling generators in a particular way. The first step toward solving this issue is to remove all the unnecessary elements and obtain a more direct illustration of the issue—if possible. Here's a first pass at that: from kanren import var, eq
from kanren.core import lconj_seq
q_lv = var()
goal_1 = lconj_seq((eq(q_lv, i) for i in range(10000)))
goal_1
# <function kanren.core.lconj_seq.<locals>.lconj_seq_goal(S)>
state_0 = {}
state_stream_1 = goal_1(state_0)
state_stream_1
# <generator object lconj_seq.<locals>.lconj_seq_goal at 0x7f6e14f580d0>
next(state_stream_1)
# RecursionError: maximum recursion depth exceeded while calling a Python object Now, we can focus exclusively on the code in |
@wrq, here's a MWE demonstrating the underlying issue: from functools import reduce
from itertools import chain
from toolz import interleave
def bind(z, g):
# Both fail for the same reason.
# return chain.from_iterable(map(g, z))
return interleave(map(g, z))
def goal_constructor(i):
def g(s):
yield (i,) + (s,)
return g
z = reduce(bind, (goal_constructor(i) for i in range(1, 10)), iter((0,)))
list(z)
# [(9, (8, (7, (6, (5, (4, (3, (2, (1, 0)))))))))]
z = reduce(bind, (goal_constructor(i) for i in range(1, 10000)), iter((0,)))
next(z)
# RecursionError: maximum recursion depth exceeded while calling a Python object |
Ok. First, I'm sorry that I haven't gotten to this sooner. I'm actually a part-time Walmart worker and a stay-at-home father, not really a professional programmer, so this has been on the backburner for me. I was able to rig this up: from functools import reduce
from itertools import chain, zip_longest
#from toolz import interleave
def interleave(*iters):
res = []
for z in zip_longest(*iters):
for _,x in enumerate(z):
res.append(x)
return res
def bind(z, g):
# Both fail for the same reason.
# return chain.from_iterable(map(g, z))
return interleave(map(g, z))
def goal_constructor(i):
def g(s):
yield (i,) + (s,)
return g
z = reduce(bind, (goal_constructor(i) for i in range(1, 10)), iter((0,)))
print(z) # debug
print(list(z)) # checking for data model weirdness
# [(9, (8, (7, (6, (5, (4, (3, (2, (1, 0)))))))))]
z = reduce(bind, (goal_constructor(i) for i in range(1, 10000)), iter((0,)))
print(next(next(iter(z)))) --- OUTPUT ---
This uses my little interleave hack from before with run-of-the-mill itertools, and then I noticed that z needs to be an iterator and cannot be a regular list. This is obviously a cumbersome way of thinking about the objects, because of the original Scheme domain would allow it. I suppose the new interleave could just "return iter(res)" ? I'm a little embarrassed to say that I'm not even confident that this is a helpful response and that I'm missing something fundamental about all of this. Edit: I just realized something. zip() will terminate on the shortest iterator, which is probably not the desired behavior? It should be zip_longest() up there. I've made the edit, but if that's what is desired, then it could just be zip(). |
No problem; I just don't want you to get the impression that this stuff is over your head, because it's not. It's just a rather context-specific problem with some unstated constraints. From a quick look at your approach, it seems like you have the right idea: i.e. delay evaluation further. This will require changes to the way that That approach could be feasible, as long as it doesn't dramatically change the stream processing semantics and has a manageable refactoring footprint. In other words, all the user-facing functions involved (e.g. the goal constructors, Also, the |
I think we might need to "flatten" this example and see what can be done from there. That would involve combining the |
The following code fails with a
RecursionError
:The error is raised in the
interleave
function fromtoolz
.The text was updated successfully, but these errors were encountered: