23 Oct 2011 12:41
Re: for-must-match
On 22 October 2011 15:00, Kevin Reid <kpreid <at> switchb.org> wrote: > On Oct 22, 2011, at 8:17, Thomas Leonard wrote: > >> Here's a patch to add list comprehensions: >> >> ? def list := [1, 2, 3] >> ? [2 * x for x in list] >> # value: [2, 4, 6] >> >> http://gitorious.org/repo-roscidus/e-core/commit/9bfacc4f748b4ea6a7cf64dc40d7bc9dd1890d38 >> >> And for map comprehensions: >> >> ? def map := ["alice" => 50, "bob" => 60] >> ? [v => k for k => v in map] >> # value: [50 => "alice", 60 => "bob"] >> >> http://gitorious.org/repo-roscidus/e-core/commit/980c8c93d41a69f242acdb5b83c9faccf918f4c3 >> >> They don't currently support the 'match' keyword, so you can't use >> them to filter (every item must be mapped to something). > > > I reject this proposal. > > 1. I am uncomfortable with it because I suspect it of violating E's syntactic conventions about scoping and evaluation order, though I would have to consult MarkM to be more precise. It probably does. However, there's also consistency with other languages to consider. The Wikipedia page has examples both ways, though most seem to favour putting the expression first: Some expr first example: [2 * x for x in items] # E (proposed) [2 * x for x in items] # Python [2 * x for (x in items)] # JavaScript [2 * x | x <- items ] # Haskell (list-of (* 2 x) (x in items)) # Scheme (non-standard) Expr last examples: for (x in items) { 2 * x } # JavaFX for (x <- items) yield 2*x # Scala The Scala syntax could work in E, although it would interfere with break(x) and involve creating a new keyword. The JavaFX syntax (without the "yield" keyword) wouldn't work because ordinary for loops are already defined to return the break() value, or null. Even if that feature were removed, it would still be impossible to tell whether a for loop was being evaluated for its value or for its side-effects. e.g. in return when (list) -> { for x in list { foo(x) } } there is no way to know whether the programmer intends to return a promise for a list of foo() results, or merely let the caller know when all the items have been processed. > 2. Furthermore, we already have the accumulator syntax which covers these use cases. I recognize that the accumulator syntax is ugly; its problem is that it is both too general and not general enough. This proposal is not general enough. I don't see why we need very general syntax. Syntax is for things you do so often that short-cuts are useful. Creating a list by processing each item in another list is a well-understood and common task, so having syntax for it makes sense (e.g. replacing map() with list comprehensions). Other things should only get special syntax once they turn out to be useful (syntax for experiments, like lambda-args, is fine, but I'm talking about enabled-by-default features for people who want to use the language, not to experiment with it). > I would rather see additional functional operations and use of lambda-args than additional syntax for operations on lists and maps; especially if they are part of a system which solves the parallel iteration problem. > > > As to your previous for-must-match pragma: I doubt its appropriateness for the language. However, it is entirely appropriate to add it as a pragma as an *experiment* -- that's why we have pragmas. You may commit for-must-match, provided that the documentation and *EVERY* code addition which supports it is marked as experimental and part of for-must-match. > > One of the reasons I don't like it is that explicit testing in 'for' (especially with the ? such-that pattern) is often useful. $ cd esrc $ grep 'for .*?.* in' **/*.emaker [ no results ] I also found no results in my code-base. > Have you considered instead adding syntax which makes a pattern "must match", i.e. converts failure into an exception (like Haskell's <at> "irrefutable patterns")? The default would be the opposite of what you have, but the syntax would make it easy to express that case where it currently isn't. It's the default that is the problem. In the code-base I'm looking at now, I count 238 for loops, of which 2 should silently skip non-matching items. The rest should throw an exception if there is no match. The default should be for the 99% case, not the 1% case (maybe other people use it differently, but these are the numbers for our code). Also, the current default tends to cause mysterious failures when something silently fails to match. By contrast, forgetting to add the "match" keyword causes a loud and obvious failure and is easily fixed. -- -- Dr Thomas Leonard http://0install.net/ GPG: 9242 9807 C985 3C07 44A6 8B9A AE07 8280 59A5 3CC1 GPG: DA98 25AE CAD0 8975 7CDA BD8E 0713 3F96 CA74 D8BA _______________________________________________ e-lang mailing list e-lang <at> mail.eros-os.org http://www.eros-os.org/mailman/listinfo/e-lang
RSS Feed