-
Notifications
You must be signed in to change notification settings - Fork 10
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
Add Clojure's seq abstraction #32
Comments
How does this proposal compare to @tuturto's |
They look pretty different to me. They both have the property of caching the calculated values. @tuturto's sequences seems like more of an alternative to generators. My seq abstraction would probably make that obsolete, since you could just use seq on a normal |
They're pretty different. Mine is a (possibly recursive) sequence defined in terms of index. Think of fibonacci:
One can iterate over it, but the iterator is mutable (because it's just a normal iterator):
gilch's approach takes any iterator and creates a new immutable iterator:
However, since it doesn't define So they're solving related, but slightly different problems. |
More precisely, it takes any iterable and makes a new lazy immutable iterable from it. The iterables are those things that you can use >>> tuple([1,2,3,4,5])
(1, 2, 3, 4, 5)
>>> tuple(iter(iter(iter([1,2,3,4,5]))))
(1, 2, 3, 4, 5)
>>> spam = iter([1,2,3])
>>> iter(spam) is spam
True
>>> iter(iter(iter(spam))) is spam
True A better optimized You can use a If you have an iterator, but want to use it more than once, the usual way of handling that in Python is to realize the iterator into a tuple, which is immutable, but still iterable. This doesn't work well if the iterator is sufficiently large. The I think we could also add a See Clojure's seq abstraction for what else we could do with this. The |
I would really love to see this in Hy. While I like using iterators, I know from first hand that some cases are hard to work with and can introduce subtle bugs. Should come up with good naming though, that separates these two from each other. Since @gilch's is closer to what clojure's sequences are, I would propose to renaming my solution to something different. |
This would be pretty great, and it seems like it wouldn't cause any trouble with Python integration. |
Actually there is one thing that worries me: how is the memory usage here? Often in Python, iterators are used when processing large data sequences, and I'm just not sure how the storage of numerous attached functions and such would work out... |
We'd have to design it carefully. My proof of concept might have a bit of a problem there. I haven't tested it enough (and have already uncovered other problems). But in principle, if you don't keep a reference to the head, the garbage collector is free to reclaim any lazy cons cells you've passed. So besides a small fixed overhead for the current value, you're not taking up any more memory than any other lazy iterator. I think Python can reuse the function bytecode and only change the values in the closures, so I'm not too worried about the functions taking up too much memory. They're also generated on the fly, so it's still lazy. |
We're running into occasional annoying problems because the ubiquitous Python iterators are mutable. Clojure doesn't have this problem because it uses the immutable seq abstraction instead. A seq can still have the lazyness of some iterables, but getting the next item won't change what the first seq means.
I've been playing around with a Python implementation of seq. Here's a rough attempt. This could easily be translated to Hy.
And a function to demonstrate the laziness.
And the demonstration:
That
iter()
call isn't required, but it demonstrates converting a mutable iterator into an immutable seq (provided nothing else has a reference to that iterator).Some more ideas:
Clojure often converts collections to seq's automatically. Rather than add that to a lot of Hy functions, we might instead have a short reader macro to do it. Although,
(seq xs)
is not that long to begin with.We could also change the
__repr__
of aSeq
to print off up to the first 20 items or something. This would make seq's a lot more friendly in the repl, and lazy Python iterables too especially, when combined with the reader macro.The text was updated successfully, but these errors were encountered: