Re: [Readable-discuss] RESTART <*..*>
Alan Manuel Gloria noted that with: > (cond > ((< x -1) (* x x)) > ((> x 1) (* x x)) > ((< x 0) (sqrt (abs x))) > (else (sqrt x))) > > ..without $, we'd have to use: > > cond > (< x -1) > * x x > (> x 1) > * x x > (< x 0) > sqrt (abs x) > else > sqrt x > > ...with $: > > cond > (< x -1) $ * x x > (> x 1) $ * x x > (< x 0) $ sqrt $ abs x > else $ sqrt x To be fair, I would write this particular case using parens and infix, as: cond ! {x < -1} {x * x} ! {x > 1} {x * x} ! {x < 0} sqrt(abs(x)) ! else sqrt(x) > but if you're using multiple expressions, you should really be using > indentation anyway. Fair enough. > (admittedly, you can also just retain the parentheses, but every > parenthesis cuts the power of t-expressions, because parentheses > disables stuff.) Well, it only disables indentation-processing stuff; you still have infix, traditional function application, and n-expression suffixes. Since this case just uses parens for traditional functional application, and it's not deeply nested, I'd do it the other way as I've shown above. This is one of those situations where there are 2 good ways; both are reasonable. I think *EITHER* approach is an improvement over traditional notation. > I feel "$" is a really good balance of something-weird (con) but > extremely useful (pro). I think "$" is *not* really something weird, because it's already in an existing language with significant use (Haskell). Granted, someone who's never used Haskell has something new to learn. But practically all programming languages have a large set of infix operations; from that point of view, t-expressions have a remarkably tiny set of special "infix" operations. --- David A. Wheeler -- Master HTML5, CSS3, ASP.NET, MVC, AJAX, Knockout.js, Web API and much more. Get web development skills now with LearnDevNow - 350+ hours of step-by-step video tutorials by Microsoft MVPs and experts. SALE $99.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122812 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
On 1/17/13, Alan Manuel Gloria wrote: > On 1/17/13, David A. Wheeler wrote: >>> Personally I'm not (yet?) a big fan of $. >> >> Not a problem. It's grown on me. Once you have it, you find that >> patterns >> where it applies are remarkably common. > > (^^)v > In support of that, consider the following: (cond ((< x -1) (* x x)) ((> x 1) (* x x)) ((< x 0) (sqrt (abs x))) (else (sqrt x))) ..without $, we'd have to use: cond (< x -1) * x x (> x 1) * x x (< x 0) sqrt (abs x) else sqrt x ...with $: cond (< x -1) $ * x x (> x 1) $ * x x (< x 0) $ sqrt $ abs x else $ sqrt x ...which is a lot nearer to the original s-expression. The only caveat is that in this form, $ is followed by a *single* expression, but if you're using multiple expressions, you should really be using indentation anyway. (admittedly, you can also just retain the parentheses, but every parenthesis cuts the power of t-expressions, because parentheses disables stuff.) Here's a better example of the intended use of $: import $ srfi srfi-45 import $ amkg object ; use for debugging define probe(x) print(x) x define lazy-construct(a d) lazy $ probe $ let ((rv #f)) set! rv $ object-construct 'cons-cell object-method-register rv 'car $ lambda () a 'set-car! $ lambda (na) $ set! a na 'cdr $ lambda () d 'set-cdr! $ lambda (nd) $ set! d nd rv -- I feel "$" is a really good balance of something-weird (con) but extremely useful (pro). Sincerely, AmkG -- Master HTML5, CSS3, ASP.NET, MVC, AJAX, Knockout.js, Web API and much more. Get web development skills now with LearnDevNow - 350+ hours of step-by-step video tutorials by Microsoft MVPs and experts. SALE $99.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122812 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
On 1/17/13, David A. Wheeler wrote: > (library > (amkg animals (1 0)) > (export cat (rename (rover dog))) > (import (only (amkg pets (1 0)) rover)) > (define cat (quote meow))) > > > Is that what you expected? Yes ^^ On 1/17/13, David A. Wheeler wrote: >> Personally I'm not (yet?) a big fan of $. > > Not a problem. It's grown on me. Once you have it, you find that patterns > where it applies are remarkably common. (^^)v >> I'm not against having a way to restart indentation; I just wanted to >> keep >> the *option* to not restart it to 0, as a matter of taste. >> Though in light of empty comments always being available, I'm ok with a >> construct that always forces indent to 0, if it's simpler. > > It's much simpler. There are some nasty subtleties in *starting* with a > non-zero indent and trying to make it "mean the obvious" in a Lisp-based > language; see the draft SRFI for more details if you're curious. It could > work in other languages, but in Scheme, it's hard because (1) the "read" > interface of Scheme is already fixed, and (2) standard Scheme doesn't > support unlimited unread-char. *Technically* R5RS and R6RS don't support unread-char, at all. However, most implementations of Scheme support some kind of unread-char, and some of them only support a 1-character unread-char. So we have adopted the limitation of requiring only 1 character lookahead, which can be done by using (let ((c (read-char port))) (unread-char c port) c). >> Another very unbaked idea: perhaps we can take a hint from typography and >> formats such as reStructuredText, markdown and emacs outline-mode (which >> all took that hint): >> Represent most structure using indentation, but some structure above that >> using several levels of headings. > > Not a crazy idea, but that would only deal with the case for multi-line that > begins on the left edge. That wouldn't deal with the "small let" case, or > anything that has some simple prefix. I know you don't care about "short > let", but *I* do :-). An interesting idea IMO. Hmm. >> I think like this direction on aesthetic grounds, but I suspect the >> practical convenience of having some reader macro entering the t-expr >> parser in the middle of s-expr parsing will prevail. > > Yes, that's my thinking too. > > --- David A. Wheeler > > -- > Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, > MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current > with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft > MVPs and experts. ON SALE this month only -- learn more at: > http://p.sf.net/sfu/learnmore_122712 > ___ > Readable-discuss mailing list > Readable-discuss@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/readable-discuss > -- Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft MVPs and experts. ON SALE this month only -- learn more at: http://p.sf.net/sfu/learnmore_122712 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
Beni Cherniavsky-Paskin: > "<*" is 2 chars, "((" is 2 chars. Some of your win here is just from using > spaces to set apart the delimiters. > Isn't this better addressed by schemes that allow [..] in place of (..): > > let [ (x cos(f(c))) > (y sin(f(c))) ] > ! dostuff x y > > which is more homoiconic by preserving the nesting level. > I feel that let's structure is truly annoying, but it's not the notation's > job to hide that if it becomes less homoiconic; I'd rather fix the > construct and use a let1 macro. I agree that let's structure in the 1-variable case is annoying (I also sometimes use a let1 macro), and I agree that it's not a notation's job to *hide* annoying structures. But if a structure is common and annoying to *use*, it's reasonable to look for notations that make it *easier* to use. Hiding bad, ease-of-use good :-). > Personally I'm not (yet?) a big fan of $. Not a problem. It's grown on me. Once you have it, you find that patterns where it applies are remarkably common. > I have even more reservations about \\ usage: >let <* x cos(f(c)) \\ y sin(f(c)) *> > where the list depth hinges on the fact that there are 2 elements between the > \\. > > I see how such constructs are appealing in-line once you're used to them, I think that's the key point. It needs to be easy for people to mentally map a construct to the underlying list structure, of course, but after a while, you learn that certain visual patterns are the "easy" way to use a construct. The same thing happens in other languages; I read the following C construct: for (i=0; i < max; i++) ... as a single trivial idea, because it's such a common pattern. > but this makes me ask: could you lift $ and/or \\ to a separate layer from > indent processing, so they remain available inside regular (..) lists? Sure, that's possible. But do we *want* to? 1. That would mean that you'd have to escape them even inside (...). 2. It mildly interferes with backwards compatibility. I'd like traditional code to mostly work "as is" - in a backward-compatible way - if it's cleanly formatted. Programs that use symbols $ or \\ would then have problems. 3. I'd like to be able to call down to the underlying reader as much as possible to implement constructs; doing this *requires* that we override processing the contents of a list, even if it already has a curly-infix reader. > I must admit I haven't even tried to keep up with your grammar work. I'll > try to take a look - the whole thing is much shorter than the one-at-a-time > mails made me think :-) Thanks! > I'm not against having a way to restart indentation; I just wanted to keep > the *option* to not restart it to 0, as a matter of taste. > Though in light of empty comments always being available, I'm ok with a > construct that always forces indent to 0, if it's simpler. It's much simpler. There are some nasty subtleties in *starting* with a non-zero indent and trying to make it "mean the obvious" in a Lisp-based language; see the draft SRFI for more details if you're curious. It could work in other languages, but in Scheme, it's hard because (1) the "read" interface of Scheme is already fixed, and (2) standard Scheme doesn't support unlimited unread-char. > Sure, it must be multi-char. I was think more in the directions of e.g. #( > ... )# but those might well be taken for things like vectors. Yes, "#(" introduces a vector comment. And "#" is busy enough; there are a lot of nonstandard Scheme extensions that start with "#", so anything starting with "#" is frankly not safe for use (it'd probably conflict with SOMETHING). > Another very unbaked idea: perhaps we can take a hint from typography and > formats such as reStructuredText, markdown and emacs outline-mode (which > all took that hint): > Represent most structure using indentation, but some structure above that > using several levels of headings. Not a crazy idea, but that would only deal with the case for multi-line that begins on the left edge. That wouldn't deal with the "small let" case, or anything that has some simple prefix. I know you don't care about "short let", but *I* do :-). > I think like this direction on aesthetic grounds, but I suspect the > practical convenience of having some reader macro entering the t-expr > parser in the middle of s-expr parsing will prevail. Yes, that's my thinking too. --- David A. Wheeler -- Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft MVPs and experts. ON SALE this month only -- learn more at: http://p.sf.net/sfu/learnmore_122712 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-di
Re: [Readable-discuss] RESTART <*..*>
Alan Manuel Gloria: > Whoa whoa whoa - there seems to be problems with SUBLIST and SPLICE! Are you suggesting there could be a... bug?!? Why, that could never happen :-). It appears that SUBLIST is the problem child here. In "unsweeten", using just SUBLIST, we have (as expected): amkg animals $ 1 0 ==> (amkg animals (1 0)) In the draft BNF, we have the unexpected: amkg animals $ 1 0 ==> ((amkg animals) (1 0)) If one pair of parens is good, I guess two is better :-). This was made worse because my test suite "correct" answers had the wrong results. My bad, sorry. Clearly the SUBLIST action is busted. I believe this fixes it: | SUBLIST hspace* i_expr1=i_expr - {$v=list(monify($head.v), $i_expr1.v);} + {$v=append($head.v, list(monify($i_expr1.v)));} I've posted the grammar with that change. Okay, let's try again. I took this: <* library \\ amkg animals $ 1 0 export cat rename $ rover dog import only amkg pets $ 1 0 rover define cat 'meow *> The draft BNF now generates: (library (amkg animals (1 0)) (export cat (rename (rover dog))) (import (only (amkg pets (1 0)) rover)) (define cat (quote meow))) Which can be reformatted as: (library (amkg animals (1 0)) (export cat (rename (rover dog))) (import (only (amkg pets (1 0)) rover)) (define cat (quote meow))) Is that what you expected? --- David A. Wheeler -- Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft MVPs and experts. ON SALE this month only -- learn more at: http://p.sf.net/sfu/learnmore_122712 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
On 1/17/13, David A. Wheeler wrote: > Alan Manuel Gloria: >> So given the above semantics, we can define an R6RS library as so: >> >> <* >> library \\ amkg animals $ 1 0 >> export >> cat >> rename $ rover dog >> import >> only >> amkg pets $ 1 0 >> rover >> >> define cat 'meow >> >> *> > > I just ran your same through my ANTLR processor, which now implements the > "sequence of i_expr" semantics. I still need to examine the draft action > rules more carefully, but even so, it came up with this: > > (library > ((amkg animals) (1 0)) > (export cat (rename (rover dog))) > (import (only ((amkg pets) (1 0)) rover)) > (define cat (quote meow))) > > That certainly seems like a plausible interpretation of the example. Do you > agree? Whoa whoa whoa - there seems to be problems with SUBLIST and SPLICE! amkg animals $ 1 0 ==> (amkg animals (1 0)) remember: define foo(x) $ cond { x = 0 } $ bar() else $ core-foo x ==> (define (foo x) (cond ((= x 0) (bar)) (else (core-foo x So the ((amkg animals) (1 0)) looks wrong here. In fact: library \\ amkg animals $ 1 0 ...should be equivalent to: library amkg animals $ 1 0 ...should be equivalent to: library amkg animals 1 0 ...And then: library (amkg animals (1 0)) So something looks wrong Sincerely, AmkG -- Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft MVPs and experts. ON SALE this month only -- learn more at: http://p.sf.net/sfu/learnmore_122712 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
On Jan 16, 2013 3:29 PM, "David A. Wheeler" wrote: > > > If we separate the 2 issues, I feel the no-blank-lines is the more > > problematic of them. In Python, I'm fine with most of my defs being > > indented because they're class methods, but couldn't live without new lines. > > Do you agree? > > I don't *exactly* agree, though you may be missing an element of sweet-expressions that makes end-on-blank-lines work. But first, my priorities. > > My current view is that the more important requirement is that the REPL and file format need to be exactly the *same* in a Lisp-based system. In Python you often cannot cut-and-paste from files into the command line ("REPL"), because Python files and the REPL have different blank-line semantics. (Technically, the Python spec only covers files, but that's a useless nuance.) That's actually a problem in Python today, and annoys me sometimes. In a Lisp such a difference would be crazy, because Lisps are programmable programming languages where experimentation is common. > I'll defer to you on this though I don't feel this is such a big problem in python; GUI shells solve it by distinguishing pressing Enter from pasting Enter, and/or by requiring ctrl+Enter (or backspacing the indent then Enter) to terminate multiline command (IIRC dreampie does the latter). Unfortunately, lisp doesn't have python's : hint that the expression will be a multiline one. It's indeed annoying in the terminal. IIRC ipython has some magic %paste syntax to paste an arbitrary block. IOW, the file/repl tension does justify a construct like this, but it's a REPL only construct... > Now for blank lines. Blank lines ending an expression actually isn't bad, even in a larger program, because of the rule that comment-only lines (possibly indented) are completely ignored, and do NOT end an expression. I agree that without that rule it'd be hideous to use, but using comment-only lines to vertically separate material actually works very cleanly. > Ah, indeed I missed that! It changes a lot of priorities in my arguments, because if I'd keep the indentation and only use this for empty lines, that feels a petty - perhaps I should just live with empty comments and not need a new construct at all; and let people who also want to reset indentation have their way... > It's not insane to use some marker to mean "end of expression", several languages do that. Indeed, sweet-expressions could be modified to that easily enough. But then users have to remember to do that after every expression. If REPL use is rare, that'd be fine. But I expect lots of people to use the REPL, often, and I want the REPL to be very pleasant to use. It's hard to beat "enter a blank line to evaluate". > Agreed. I absolutely hate SQL prompts that don't execute until I add a ; > Well, the current notation is obviously not a disaster, since we've written programs without it. But when the variables involve modest amounts of calculation, it gets harder to see what you're doing than I'd prefer, because it's easy to suddenly require more paren-nesting than is typical in other languages. > > Contrast: > > let ((x cos(f(c > ! dostuff x > > with: > let <* x cos(f(c)) *> > ! dostuff x > > In one-variable lets, a common mistake is to forget to embed the variable in double-parens. Since the parens are also usually used for the expression calculation, it can be easy to miss. Making it possible to visually distinguish the outer "parens" that create the variable list, from the internal parens used for the expression, makes it clearer which parens are more structural vs. the ones involved in the variable calculation. That, in turn, makes it easier to notice the omission of doubled parens for one variable. > "<*" is 2 chars, "((" is 2 chars. Some of your win here is just from using spaces to set apart the delimiters. Isn't this better addressed by schemes that allow [..] in place of (..): let [ (x cos(f(c))) (y sin(f(c))) ] ! dostuff x y which is more homoiconic by preserving the nesting level. I feel that let's structure is truly annoying, but it's not the notation's job to hide that if it becomes less homoiconic; I'd rather fix the construct and use a let1 macro. > or: > let <* x $ cos $ f c *> > ! dostuff x > Personally I'm not (yet?) a big fan of $. I have even more reservations about \\ usage: let <* x cos(f(c)) \\ y sin(f(c)) *> where the list depth hinges on the fact that there are 2 elements between the \\. I see how such constructs are appealing in-line once you're used to them, but this makes me ask: could you lift $ and/or \\ to a separate layer from indent processing, so they remain available inside regular (..) lists? > As it turns out, the new ruleset for <*...*> that I just posted is quite simple, and it basically only requires one extra line in the spec to handle the on-the-same-line case. > I must admit I haven't even tried to keep up with your grammar work. I'll try to take a look - the whole thi
Re: [Readable-discuss] RESTART <*..*>
Beni Cherniavsky-Paskin: > Summary: I only buy the first of the use cases; I think this construct will > be rarely used and want the sematics to be as simple as possible; I propose > some alternative ideas below. First of all, thanks SO MUCH for posting!! I'm a big believer in feedback, so I really appreciate your time. I agree that the first use case (multi-line libraries) is more important, which is why I put it first. I do think the other use case is relevant, though, especially if we can resolve both at once. I completely agree that the final semantics need to be "as simple as possible". In general, I try to do a lot of experimentation and out-of-the-box thinking before deciding on something specific, so please don't assume that some more complicated draft structure is the "final word". > If we separate the 2 issues, I feel the no-blank-lines is the more > problematic of them. In Python, I'm fine with most of my defs being > indented because they're class methods, but couldn't live without new lines. > Do you agree? I don't *exactly* agree, though you may be missing an element of sweet-expressions that makes end-on-blank-lines work. But first, my priorities. My current view is that the more important requirement is that the REPL and file format need to be exactly the *same* in a Lisp-based system. In Python you often cannot cut-and-paste from files into the command line ("REPL"), because Python files and the REPL have different blank-line semantics. (Technically, the Python spec only covers files, but that's a useless nuance.) That's actually a problem in Python today, and annoys me sometimes. In a Lisp such a difference would be crazy, because Lisps are programmable programming languages where experimentation is common. Now for blank lines. Blank lines ending an expression actually isn't bad, even in a larger program, because of the rule that comment-only lines (possibly indented) are completely ignored, and do NOT end an expression. I agree that without that rule it'd be hideous to use, but using comment-only lines to vertically separate material actually works very cleanly. It's not insane to use some marker to mean "end of expression", several languages do that. Indeed, sweet-expressions could be modified to that easily enough. But then users have to remember to do that after every expression. If REPL use is rare, that'd be fine. But I expect lots of people to use the REPL, often, and I want the REPL to be very pleasant to use. It's hard to beat "enter a blank line to evaluate". But this approach does have a downside with long library declarations (and similar structures). In these cases, the endless indentation *and* the blank lines ending expressions both start to get annoying. Thus, the <* ... *> proposal. > > Now let's look at the second use case. > > The sweet-expression notation cleanly handles cases where let-expression > > variables have complex values (e.g., using \\), but for simple cases > > (1-2 variables having short initial values) ... > I completely don't get it. > What's wrong about ((x 5) (y 7)) or (x{5} y{7}), > and why is <* x 5 *> or <* (x 5) *)> any better? > When compressing nested lists on one line, parens are the - clearest way to > represent structure. > Specifically, I dislike the usage where <* x y *> implies a double list by > restarting the multiple-items-on-a-"line" rule. While I see the consistent > logic of this semantics, it's IMHO way too hard to scan this visually as a > double list - a problem ((...)) doesn't have. Well, the current notation is obviously not a disaster, since we've written programs without it. But when the variables involve modest amounts of calculation, it gets harder to see what you're doing than I'd prefer, because it's easy to suddenly require more paren-nesting than is typical in other languages. Contrast: let ((x cos(f(c ! dostuff x with: let <* x cos(f(c)) *> ! dostuff x or: let <* x $ cos $ f c *> ! dostuff x In one-variable lets, a common mistake is to forget to embed the variable in double-parens. Since the parens are also usually used for the expression calculation, it can be easy to miss. Making it possible to visually distinguish the outer "parens" that create the variable list, from the internal parens used for the expression, makes it clearer which parens are more structural vs. the ones involved in the variable calculation. That, in turn, makes it easier to notice the omission of doubled parens for one variable. > As I see it, we need some solution for the very-long-form problem, while > one-liner-let is a solved problem. > If restricting <* .. *> to EOL - or even requiring them to stand alone on a > line - makes for a simpler spec, I'd much rather see that rather than fine > tuning the inline semantics. An excellent point. Yes, I agree that simplicity (of spec and implementation) is really important. The older experimental rulesets for <* ... *> we
Re: [Readable-discuss] RESTART <*..*>
On Jan 15, 2013 2:57 PM, "David A. Wheeler" wrote: > Sweet-expressions without restart lists (<* ... *>) > work well in a vast number of circumstances. > However, they can be somewhat awkward for two typical use cases: > > > A long sequence of definitions contained within an initial statement. > This situation occurs in many library definition structures such as > Scheme R7RS define-library and in some larger data structures. > A let-style statement with one or two variables > with short initial values. > Summary: I only buy the first of the use cases; I think this construct will be rarely used and want the sematics to be as simple as possible; I propose some alternative ideas below. > > Let's begin with the first use case. > When there is a long sequence of definitions contained within an > initial statement, and no special notation like restart lists, > all the definitions in the long sequence must be > indented and none can be separated by a blank line > (since that would end the entire sequence, not just a definition). > Indenting almost an entire file is annoying, and needing no blank lines > for that long invites mistakes. If we separate the 2 issues, I feel the no-blank-lines is the more problematic of them. In Python, I'm fine with most of my defs being indented because they're class methods, but couldn't live without new lines. Do you agree? >... > > Now let's look at the second use case. > The sweet-expression notation cleanly handles cases where let-expression > variables have complex values (e.g., using \\), but for simple cases > (1-2 variables having short initial values) > it can take up more vertical space than traditional formatting. > Using a leading "$" takes up somewhat less vertical space, but it still > takes up an additional line for a trivial case, it does not work > the same way for let expressions with 2 variables, > and David A. Wheeler thinks it is a rather unclear construction. > You can also use parenthetical notation directly, but this is > relatively ugly and it is annoying to need to do this for a common case. I completely don't get it. What's wrong about ((x 5) (y 7)) or (x{5} y{7}), and why is <* x 5 *> or <* (x 5) *)> any better? When compressing nested lists on one line, parens are the - clearest way to represent structure. Specifically, I dislike the usage where <* x y *> implies a double list by restarting the multiple-items-on-a-"line" rule. While I see the consistent logic of this semantics, it's IMHO way too hard to scan this visually as a double list - a problem ((...)) doesn't have. As I see it, we need some solution for the very-long-form problem, while one-liner-let is a solved problem. If restricting <* .. *> to EOL - or even requiring them to stand alone on a line - makes for a simpler spec, I'd much rather see that rather than fine tuning the inline semantics. >... > let ; Using \\ takes up a lot of vertical space in simple cases > \\ > x 5 > {x + x} > > let > \\ > x 5 > y 7 > {x + x} > > let ; Less vertical space, but 1 variable only > $ x 5 > {x + 5} > > ; Note "$ x 5 $ y 7" isn't right; that maps to ((x 5 (y 7))). >... I agree that "two-liner-let" is not a solved problem. We can either cram it on 1 line, or nicely spread on 1+N lines using \\, but not on N lines. IMO this goes deeper than just let but I don't think abusing <*..*> is an improvement. I'll try to post thoughts on this in the z language thread. > > Here are examples of the same constructs, using restart lists: > > > define-library > example grid > export make rows cols ref each rename(put! set!) > import scheme(base) > begin <* > > define make(n m) > let (grid(make-vector(n))) > ... > *> > IMHO, it's very ugly that "example grid ..." are indented when the body of the library isn't. Indentation should be (at least) non-decreasing! If I were to use a construct like this, I'd either have "define ..." indented deeper (only using <*..*> for blank line freedom), or flatten the containing lists at indent zero (on the theory it should actually be negative): <* define-library example grid export make rows cols ref each rename(put! set!) import scheme(base) <* begin define make(n m) let (grid(make-vector(n))) ... *> *> I'm deliberately restricting <* to the head of the list. I see it as an esoteric construct, and this is the simplest least-surprise version. > > The restart list symbols are carefully chosen. > The characters < and > are natural character pairs that are > available in ASCII. > What is more, they are not delimiters, so any underlying > Scheme reader will not immediately stop on reading them > (making it easier to reuse). Which is also a weakness IMHO. Visually, < and > don't feel like a list start/end, at least not to lisp eyes. ([{ / }]) have a history as list delimiters, < / > not so much. Which leads me to the following idea: let the list be started / ended by (...), but have a notation that *only* [re]starts t-exp
Re: [Readable-discuss] RESTART <*..*>
Alan Manuel Gloria: > So given the above semantics, we can define an R6RS library as so: > > <* > library \\ amkg animals $ 1 0 > export > cat > rename $ rover dog > import > only > amkg pets $ 1 0 > rover > > define cat 'meow > > *> I just ran your same through my ANTLR processor, which now implements the "sequence of i_expr" semantics. I still need to examine the draft action rules more carefully, but even so, it came up with this: (library ((amkg animals) (1 0)) (export cat (rename (rover dog))) (import (only ((amkg pets) (1 0)) rover)) (define cat (quote meow))) That certainly seems like a plausible interpretation of the example. Do you agree? --- David A. Wheeler -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
Alan Manuel Gloria: > 2. "superlist" just calls the top-level "i_expr" repeatedly, creating > a list of items, and terminating upon finding a *>, returning the > yielded list. I had originally done this, and I then switched over to a more complicated set of productions. I've now recently switched back to that much simpler "sequence of i_expr" semantic, and I think that's the "right" meaning. I've posted my latest to the devel branch in our SourceForge git repository. Sadly, there's an annoying tooling problem with treating superlist/restart list/whatever as just a "sequence of i_expr", which is why I had switched from the simple sequence to a more complicated set of productions. To make the "sequence of i_expr" concept work, you have to be able to end a restart list on the *SAME LINE* that it starts. Previously, an i_expr could *ONLY* end at the end of a line (possibly preceded by ";", and given the exception of the special case of splice). Because that was true, that made for a really clear potential ending point for an i_expr (in the normal case). No big deal, you say, just add a new branch in i_expr to allow "head empty". Well, yes, and I've done that. However, once you do that, ANTLR generates a huge number of warnings about various ambiguities. As far as I can tell, the ANTLR warnings are technically correct but spurious. There's a huge number of them, and they're painful to track through. But if I understand them correctly, the issue is straightforward. If you allow "head empty" to end an i_expr, that means that *any* sequence of one or more n_expr on a line could end an i_expr, because any sequence of one or more n_expr can be a head. So technically "a b" and "a" both match an i_expr if "head empty" is allowed as an i_expr. This is basically the same situation as the "trailing else" matching in many programming languages. It's also trivially disambiguated, just like "trailing else". In this case, if you are reading in a line, simply follow the longest match, or the earliest matching branches in a production where more than one case could match, to disambiguate the cases. In fact, ANTLR does this, and it seems to work just fine. What's *weird* is that I can't seem to get ANTLR to shut up about it when it generates the grammar. ANTLR has a "greedy" option specifically to disable warnings when you want it to disambiguate branches this way. But in this case I can't seem to make ANTLR happy. That makes *me* sad, because I'd like as much confidence as possible that the specification is right, and I've been using ANTLR to help me gain that confidence. ANTLR's greedy option works in other cases, so I'm not sure why it's ignoring me in this case. That said, I think this "sequence of i-expression" semantic is pretty clearly the right semantic. For one thing, the productions I come up with are simple and clean. I haven't checked the action rules carefully yet, but my first try at them seems reasonably right too. It seems to be easy to reason about and produce the "expected results". Here's my current try, fixes welcome: restart_tail returns [Object v]: i_expr rt1=restart_tail {$v = cons($i_expr.v, $rt1.v);} | RESTART_END {$v = null;} ; restart_list returns [Object v]: RESTART hspace* comment_eol* restart_tail {$v = $restart_tail.v;} ; head returns [Object v] ... | restart_list hspace* (rest1=rest {$v = cons($restart_list.v, $rest1.v) ; } | empty{$v = list($restart_list.v); } ) rest returns [Object v] ... | restart_list hspace* (rest2=rest {$v = cons($restart_list.v, $rest2.v);} | empty {$v = list($restart_list.v);} ) i_expr returns [Object v] : head ... | empty {$v = monify($head.v);} /* "head empty" - RESTART_END next */ )) ... Thoughts? --- David A. Wheeler -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
> Okay here's the concrete semantics I propose: > > 1. The "head" production is the part that looks for the <*. Upon > finding a <*, it consumes any number of horizontal spaces, line > comments, and multiline/datum comments. It then enters "superlist" > production > > 2. "superlist" just calls the top-level "i_expr" repeatedly, creating > a list of items, and terminating upon finding a *>, returning the > yielded list. > > 3. When "superlist" returns, "head" just takes its returned value and > takes it as a single item, and continues on its merry way looking for > n-expressions and superlists after the *>. > > The third part allows: > > let <* x 5 \\ y 6 *> {x + y} So given the above semantics, we can define an R6RS library as so: <* library \\ amkg animals $ 1 0 export cat rename $ rover dog import only amkg pets $ 1 0 rover define cat 'meow *> Thoughts? Sincerely, AmkG -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
On 1/16/13, David A. Wheeler wrote: > Alan Manuel Gloria: > >> Okay, the *semantics* is confusing to me. >> >> How are the following suppose to parse? > > The answer is, "whatever we decide it should be" :-). So now is a perfect > time to discuss it. And if some combination seems to be nonsense, we can > declare it an error. > > BTW, Don't pay serious attention to the sweet.g file's action statements for > restart_list. I'm doing a lot of experiments with them and they're almost > certainly "wrong" right now. So with that caveat... > >> library foo >> <* begin >> >> define cat 'meow >> >> define dog 'woof >> >> *> >> >> I assume: >> >> (library foo >> (begin >> (define cat 'meow) >> (define dog 'woof) >> ) > > Yes, that's what I think too. > > But that's if we allow same-line and later-lines simultaneously at *all*. > My current draft BNF *does* allow this (by intent), but if the semantics are > too complicated, we could just say either (1) it must be all on one line, or > (2) the start has to be followed by hspace* comment_eol. > > But let's continue the thought... > >> But what happens with this? >> >> library foo >> <* begin print(x) >> >> define cat 'meow >> define dog 'woof >> >> *> > > To be honest, I don't know of a use case that suggests any particular > semantic. I can image that this *might* mean: > > (library foo > (begin > (print x) > (define cat 'meow) > (define dog 'woof))) > > Though perhaps other semantics would make sense. > >> How about this? >> >> let <* x 5 *> { x + 42 } > > I think t that should mean: > (let ((x 5)) (+ x 42) > > Basically, <*...*> wraps an extra () around an expression. Since "x 5" means > (x 5), "<* x 5 *>" == ((x 5)). And since what follows <*...*> is just > another parameter, that parameter should be treated normally. > >> Or worse, this? >> >> let <*x y >>w z *> >> 42 > > I'm guessing that should perhaps be: > (let (x y (w z)) 42) > > Perhaps we'd better off to not allow stuff to be on both the same line and > on later lines, at least at first. The "library definition" use case and > the "let" use case are easily distinguished that way. That might mean you'd > have a multi-line statement with a "begin" on its own line, but if it's a > long sequence of definitions, that may not be a big deal. > Okay here's the concrete semantics I propose: 1. The "head" production is the part that looks for the <*. Upon finding a <*, it consumes any number of horizontal spaces, line comments, and multiline/datum comments. It then enters "superlist" production 2. "superlist" just calls the top-level "i_expr" repeatedly, creating a list of items, and terminating upon finding a *>, returning the yielded list. 3. When "superlist" returns, "head" just takes its returned value and takes it as a single item, and continues on its merry way looking for n-expressions and superlists after the *>. The third part allows: let <* x 5 \\ y 6 *> {x + y} >> You know, maybe we should call it "SUPERLIST" in contrast with "SUBLIST". >> ^^;;; > > You're smiling, but that's not an entirely insane name. It's hard to think > of a good name for this. MEGALIST UBERLICHST OVERLYPRETENTIOUSADJECTIVELIST Sincerely, AmkG -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
Alan Manuel Gloria: > Okay, the *semantics* is confusing to me. > > How are the following suppose to parse? The answer is, "whatever we decide it should be" :-). So now is a perfect time to discuss it. And if some combination seems to be nonsense, we can declare it an error. BTW, Don't pay serious attention to the sweet.g file's action statements for restart_list. I'm doing a lot of experiments with them and they're almost certainly "wrong" right now. So with that caveat... > library foo > <* begin > > define cat 'meow > > define dog 'woof > > *> > > I assume: > > (library foo > (begin > (define cat 'meow) > (define dog 'woof) > ) Yes, that's what I think too. But that's if we allow same-line and later-lines simultaneously at *all*. My current draft BNF *does* allow this (by intent), but if the semantics are too complicated, we could just say either (1) it must be all on one line, or (2) the start has to be followed by hspace* comment_eol. But let's continue the thought... > But what happens with this? > > library foo > <* begin print(x) > > define cat 'meow > define dog 'woof > > *> To be honest, I don't know of a use case that suggests any particular semantic. I can image that this *might* mean: (library foo (begin (print x) (define cat 'meow) (define dog 'woof))) Though perhaps other semantics would make sense. > How about this? > > let <* x 5 *> { x + 42 } I think t that should mean: (let ((x 5)) (+ x 42) Basically, <*...*> wraps an extra () around an expression. Since "x 5" means (x 5), "<* x 5 *>" == ((x 5)). And since what follows <*...*> is just another parameter, that parameter should be treated normally. > Or worse, this? > > let <*x y >w z *> > 42 I'm guessing that should perhaps be: (let (x y (w z)) 42) Perhaps we'd better off to not allow stuff to be on both the same line and on later lines, at least at first. The "library definition" use case and the "let" use case are easily distinguished that way. That might mean you'd have a multi-line statement with a "begin" on its own line, but if it's a long sequence of definitions, that may not be a big deal. > You know, maybe we should call it "SUPERLIST" in contrast with "SUBLIST". > ^^;;; You're smiling, but that's not an entirely insane name. It's hard to think of a good name for this. --- David A. Wheeler -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
Okay, the *semantics* is confusing to me. How are the following suppose to parse? library foo <* begin define cat 'meow define dog 'woof *> I assume: (library foo (begin (define cat 'meow) (define dog 'woof) ) But what happens with this? library foo <* begin print(x) define cat 'meow define dog 'woof *> How about this? let <* x 5 *> { x + 42 } Or worse, this? let <*x y w z *> 42 Sincerely, AmkG P.S. You know, maybe we should call it "SUPERLIST" in contrast with "SUBLIST". ^^;;; -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
The bit: ; Note "$ x 5 $ y 7" isn't right; that maps to ((x 5 (y 7))). ..should be better placed in a paragraph - I for one tend to skim over source code in the SRFI. -- The bit: Changing all of sweet-expressions, just to handle this particular case, does not seem warranted. ...this doesn't seem to scan well. It seems to introduce an argument to support a position (don't change all of sweet-expressions) but the paragraph it's in doesn't look like it introduces the opposing position. -- You might want to juxtapose: let \\ x $ foo bar use x versus: let <* x $ foo bar *> use x I suggest you use something similar to what you did in readable.sourceforge.net: use a table so that both examples are side-by-side. I also suggest using the given example above rather than (let ((x 5)) (+ x x)), since it gives a better justification for using RESTARTBEGIN / RESTARTEND : We want to use "foo bar" not "foo(bar)" for stylistic reasons (i.e. foo is a "command" whose return status we want to know, not a "function" that just computes something). -- This bit: begin <* Looks wrong. Shouldn't that be: <* begin ?? Of course, it depends on what, exactly, is meant by <* *>. So maybe: "begin . <*" ?? Sincerely, AmkG -- Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery and much more. Keep your Java skills current with LearnJavaNow - 200+ hours of step-by-step video tutorials by Java experts. SALE $49.99 this month only -- learn more at: http://p.sf.net/sfu/learnmore_122612 ___ Readable-discuss mailing list Readable-discuss@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/readable-discuss
Re: [Readable-discuss] RESTART <*..*>
Okay, I've tried to write down my thoughts on WHY I think restart lists are a good idea. Comments welcome. A better name is welcome for sure :-). BTW, I have a draft BNF and action rules, but don't take them seriously for restart lists; I used them more for experimentation. --- David A. Wheeler Restart lists (<* ... *>) Sweet-expressions without restart lists (<* ... *>) work well in a vast number of circumstances. However, they can be somewhat awkward for two typical use cases: A long sequence of definitions contained within an initial statement. This situation occurs in many library definition structures such as Scheme R7RS define-library and in some larger data structures. A let-style statement with one or two variables with short initial values. Let's begin with the first use case. When there is a long sequence of definitions contained within an initial statement, and no special notation like restart lists, all the definitions in the long sequence must be indented and none can be separated by a blank line (since that would end the entire sequence, not just a definition). Indenting almost an entire file is annoying, and needing no blank lines for that long invites mistakes. For example, here's an example from the R7RS Scheme specification for define-library: (define-library (example grid) (export make rows cols ref each (rename put! set!)) (import (scheme base)) (begin (define (make n m) (let ((grid (make-vector n))) (do ((i 0 (+ i 1))) ((= i n) grid) (let ((v (make-vector m #f alse))) (vector-set! grid i v) (define (rows grid) (vector-length grid)) (define (cols grid) (vector-length (vector-ref grid 0))) (define (ref grid n m) (and (< -1 n (rows grid)) (< -1 m (cols grid)) (vector-ref (vector-ref grid n) m))) (define (put! grid n m v) (vector-set! (vector-ref grid n) m v This is easily reformatted into this sweet-expression: define-library example grid export make rows cols ref each rename(put! set!) import scheme(base) begin define make(n m) let (grid(make-vector(n))) do (i(0 {i + 1})) ! {i = n} grid ! let (v(make-vector(m #f alse))) vector-set!(grid i v) define rows(grid) vector-length(grid) define cols(grid) vector-length(vector-ref(grid 0)) define ref(grid n m) and {-1 < n < rows(grid)} {-1 < m < cols(grid)} vector-ref vector-ref(grid n) m define put!(grid n m v) vector-set!(vector-ref(grid n) m v) But there are reasons that sweet-expressions are defined the way they are. It is fundamental that a child line is indented from its parent, since that is the point of indentation. Opening a parentheses intentionally disables indentation processing; this is what developers typically expect (note that both Python and SRFI-49 do this), and it also makes sweet-expressions very backwards-compatible with traditional s-expressions. Ending a definition at a blank line is very convenient for interactive use, and interactive and file notation should be identical (since people often switch between them). Changing all of sweet-expressions, just to handle this particular case, does not seem warranted. Now let's look at the second use case. The sweet-expression notation cleanly handles cases where let-expression variables have complex values (e.g., using \\), but for simple cases (1-2 variables having short initial values) it can take up more vertical space than traditional formatting. Using a leading "$" takes up somewhat less vertical space, but it still takes up an additional line for a trivial case, it does not work the same way for let expressions with 2 variables, and David A. Wheeler thinks it is a rather unclear construction. You can also use parenthetical notation directly, but this is relatively ugly and it is annoying to need to do this for a common case. A similar argument applies to do-expressions, and these are not at all unusual in Scheme code: let ; Using \\ takes up a lot of vertical space in simple cases \\ x 5 {x + x} let \\ x 5 y 7 {x + x} let ; Less vertical space, but 1 variable only $ x 5 {x + 5} ; Note "$ x 5 $ y 7" isn't right; that maps to ((x 5 (y 7))). ; The two-variable format can be surprising and does not let the ; programmer emphasize the special nature of the variable assignments ; (compared to the later expressions in a let statement). let x(5) y(7) {x + 5} let (x(5)) ; Use parentheses {x + x} let (x(5) y(7)) {x + x} A restart list is surrounded by the markers <* and *>. The <* and *> represent opening and closing parentheses, but restart indentation processing at the left edge instead of disabling indentation processing. The purpose of restart lists is to make it easy to clearly express these and similar use cases. In a restart list, the rest of the text after the initial <* is treated specially. That'