FascinatedBox / lily

Interpreted language focused on expressiveness and type safety.
http://lily-lang.org
MIT License
1.08k stars 38 forks source link

[suggestion] Possible implementation of Iterators #264

Closed stevedonovan closed 7 years ago

stevedonovan commented 8 years ago

It would be nice if for x in iter: { .... } had some sensible behaviour. The trouble with using lambdas everywhere is that they have limitations - I found they cannot themselves contain blocks.

Here is one possible interpretation of iter; it is a function (=>Option[A]). One keeps calling it and unwrapping the result (which is x: A) until None is returned. Closures make this style very flexible.

How about for x in [10,5,2]: { ... }? One way is for classes that are iterable to expose a method called __iter which returns the above kind of function.

But then, what does iteration over a Hash mean? One approach is that the type A becomes Tuple[K,V]. More convenient if there's tuple unpacking; for (k,v) in hash: {...}. There's a fair amount of temporary object generation that happens implicitly, though!

FascinatedBox commented 8 years ago

Lambdas cannot contain blocks.

I'm curious as to what you're trying to do, and more specific as to how it's not working. If you need anonymous blocks, that's an easy feature to add. If this is about how blocks are broken, I've got plans to change how jumps will be done soon. The new jumps (they're relative instead of absolute) will solve some of the closure problems.

For iteration, I hesitate to add special methods now. There's no virtual functions, and it's too early to discuss that I feel. More importantly, traits are missing, and this seems a feature that begs for traits. I want to add traits all at once, instead of piecemeal. Gotta make sure they're done right.

You've also identified a problem: Iteration is different for different value types, and that will need to be addressed.

I rather like the eaching/mapping methods that are already present within the library, and this would add a secondary style of iteration in combination with what already exists. Before I do that, I'd like to first find out more of what you're missing within lambdas to help with that.

stevedonovan commented 8 years ago

Yes, I noted that a multi-line lambda could not itself contain blocks, which is a limitation.

As for virtual functions, a lot of that can be done with structural typing - this type contains a certain method of the correct signature, so it matches. Go uses this with its 'interface' feature to avoid the Java problem of types having to be explicit up front about what interfaces it will implement. But I'm not a language designer - I only claim experience with implementation ;)

I await traits with interest! What language is the model?

stevedonovan commented 8 years ago

My colleague is learning Rust, so I've become interested. Rust traits would definitely be a useful addition - very elegant form of constraints on generic functions which C++ sorely lacks.

FascinatedBox commented 8 years ago

For traits, I plan to look toward a mix of Rust, Haskell, and Scala. The tricky part is going to be getting Traits to work with higher kinded types. My thinking is that I want traits first, and then to knock them around for a while. Once those are settled, then launching up and doing System F, HKT, and maybe rank-2 after. I still need to do a lot of research as to how HKT interacts with inheritance

I'm clueless enough about traits right now that I'm going to leave it as a mostly unanswered question. What's likely to happen, are at least:

stevedonovan commented 8 years ago

Absolutely agreed - implicit stuff is hard to reason about. You do have the 'legacy' class inheritance model to carry around, and people have known about its limitations for years.

FascinatedBox commented 7 years ago

Sometimes I like to leave issues open just in case I change my mind or some new thought comes along. For this, I remain convinced that Iterator should be a trait, and I'm a little more certain of how I want to implement those. I fully agree that iteration should be done by pattern matching on an Option result. Eventually, I may swap out each_* functions for iter_* functions.

When iterators do land, I think it would be nice though if the brace body was collected as a closure/inner function. This would then allow the syntax you're describing, while also providing callers with a way of choosing the kind of iteration they want.

Unfortunately, traits are a ways off. I want to do more tooling work so that I can smoothly introduce them in, unlike how enums and classes were introduced.