-
-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: