Re: [racket-dev] Code micro-level organization
On 05/30/2012 03:40 PM, Eli Barzilay wrote: Now, lets imagine that instead of a simple `' hole, there are two kinds of holes with an up or a down direction -- this leads to this kind of a syntax: (○ foo bar baz (substring ↑ 3 8) (string-trim ↑) (let ([str ↑]) ↓) (and (regexp-match? #rx^[a-z].*[a-z]$ str) ↓) (string-append * str *)) where you can read `↑' as the above and `↓' as the below. It seems like `↑' is another way to not name expressions (i.e. a pointless style :D), and `↓' is handled just fine by internal definitions. This is equivalent, currently defined, has less nesting, and avoids a rename: (define orig-str foo bar baz) (define sub (substring orig-str 3 8)) (define str (string-trim sub)) (define m (regexp-match? #rx^[a-z].*[a-z]$ str)) (and m (string-append * str *)) A `define*' form like Jay (and I) want would make these kinds of things less error-prone and allow names to be reused: (define* ↑ foo bar baz) (define* ↑ (substring ↑ 3 8)) (define* str (string-trim ↑)) (define* ↑ (regexp-match? #rx^[a-z].*[a-z]$ str)) (and ↑ (string-append * str *)) It's still pretty wordy, though. Even if I had `define*' I'd be tempted to go with my current favorite idiom, which trades wordiness for a nesting level: (let* ([↑foo bar baz] [↑(substring ↑ 3 8)] [str (string-trim ↑)] [↑(regexp-match? #rx^[a-z].*[a-z]$ str)]) (and ↑ (string-append * str *))) I occasionally get annoyed by how deeply these can get nested. I feel your pain, man. Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Code micro-level organization
How about a define* that is exactly like let* without the additional indentation level? E.g.: (define* [↑ foo bar baz] [↑ (substring ↑ 3 8)] [str (string-trim ↑)] [↑ (regexp-match? #rx^[a-z].*[a-z]$ str)]) (and ↑ (string-append * str *)) Laurent Le 31 mai 2012 19:04, Neil Toronto neil.toro...@gmail.com a écrit : On 05/30/2012 03:40 PM, Eli Barzilay wrote: Now, lets imagine that instead of a simple `' hole, there are two kinds of holes with an up or a down direction -- this leads to this kind of a syntax: (○ foo bar baz (substring ↑ 3 8) (string-trim ↑) (let ([str ↑]) ↓) (and (regexp-match? #rx^[a-z].*[a-z]$ str) ↓) (string-append * str *)) where you can read `↑' as the above and `↓' as the below. It seems like `↑' is another way to not name expressions (i.e. a pointless style :D), and `↓' is handled just fine by internal definitions. This is equivalent, currently defined, has less nesting, and avoids a rename: (define orig-str foo bar baz) (define sub (substring orig-str 3 8)) (define str (string-trim sub)) (define m (regexp-match? #rx^[a-z].*[a-z]$ str)) (and m (string-append * str *)) A `define*' form like Jay (and I) want would make these kinds of things less error-prone and allow names to be reused: (define* ↑ foo bar baz) (define* ↑ (substring ↑ 3 8)) (define* str (string-trim ↑)) (define* ↑ (regexp-match? #rx^[a-z].*[a-z]$ str)) (and ↑ (string-append * str *)) It's still pretty wordy, though. Even if I had `define*' I'd be tempted to go with my current favorite idiom, which trades wordiness for a nesting level: (let* ([↑foo bar baz] [↑(substring ↑ 3 8)] [str (string-trim ↑)] [↑(regexp-match? #rx^[a-z].*[a-z]$ str)]) (and ↑ (string-append * str *))) I occasionally get annoyed by how deeply these can get nested. I feel your pain, man. Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Code micro-level organization
(sorry for the bad indentation, writing s-exps on a phone predictive keyboard is painful...) Le 31 mai 2012 19:21, Laurent laurent.ors...@gmail.com a écrit : How about a define* that is exactly like let* without the additional indentation level? E.g.: (define* [↑ foo bar baz] [↑ (substring ↑ 3 8)] [str (string-trim ↑)] [↑ (regexp-match? #rx^[a-z].*[a-z]$ str)]) (and ↑ (string-append * str *)) Laurent Le 31 mai 2012 19:04, Neil Toronto neil.toro...@gmail.com a écrit : On 05/30/2012 03:40 PM, Eli Barzilay wrote: Now, lets imagine that instead of a simple `' hole, there are two kinds of holes with an up or a down direction -- this leads to this kind of a syntax: (○ foo bar baz (substring ↑ 3 8) (string-trim ↑) (let ([str ↑]) ↓) (and (regexp-match? #rx^[a-z].*[a-z]$ str) ↓) (string-append * str *)) where you can read `↑' as the above and `↓' as the below. It seems like `↑' is another way to not name expressions (i.e. a pointless style :D), and `↓' is handled just fine by internal definitions. This is equivalent, currently defined, has less nesting, and avoids a rename: (define orig-str foo bar baz) (define sub (substring orig-str 3 8)) (define str (string-trim sub)) (define m (regexp-match? #rx^[a-z].*[a-z]$ str)) (and m (string-append * str *)) A `define*' form like Jay (and I) want would make these kinds of things less error-prone and allow names to be reused: (define* ↑ foo bar baz) (define* ↑ (substring ↑ 3 8)) (define* str (string-trim ↑)) (define* ↑ (regexp-match? #rx^[a-z].*[a-z]$ str)) (and ↑ (string-append * str *)) It's still pretty wordy, though. Even if I had `define*' I'd be tempted to go with my current favorite idiom, which trades wordiness for a nesting level: (let* ([↑foo bar baz] [↑(substring ↑ 3 8)] [str (string-trim ↑)] [↑(regexp-match? #rx^[a-z].*[a-z]$ str)]) (and ↑ (string-append * str *))) I occasionally get annoyed by how deeply these can get nested. I feel your pain, man. Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Code micro-level organization
I was clapping through the majority of your email. I want define* so bad. I use compose and curry a lot (even though I know their performance problems) because it don't have to name things. I like the idea of the - thing with the down and up arrows. I see a value in both arrows. I also like Jon's suggestion of a 'last' id... although I'd also want 0 through n or something to refer to so many spots back. Jay On Wed, May 30, 2012 at 3:40 PM, Eli Barzilay e...@barzilay.org wrote: I'm going to ramble a bit about organizing code, trying to look for an idea for a good solution -- so spread a few kgs of salt over the following (if you care to read it). The problem that I'm talking about has several manifestations. The most obvious one is code-drift towards the RHS. A less obvious problem is how it's sometimes hard to read code. To use a cooked up example: (let ([str (string-trim (substring foo bar baz 3 8))]) (and (regexp-match? #rx^[a-z].*[a-z]$ str) (string-append * str *))) to read this, you start from the string literal, then read the `substring' expression, then `string-trim', then the `let' binding, then the `and' and finally the `string-append'[*]. To relate this to the above: besides the right-drift (which is of course very minor here), it takes time to internalize the rules of the language that leads to this, which is a problem for people new to functional programming with it's heavy use of nested function calls. More than that, I think that it's also a problem for *experienced* hackers too -- to see what I mean, open up any random piece of code that deals with an area you're not familiar with, and try to read through it. Personally, I often find myself in such situations reading the actual ordering as I go through the code, and that's fragile since I need to keep mental fingers at various locations in the code in question, sometimes even using my real fingers... You'd probably recognize that there's a whole bunch of tools that are trying to make things better. A few random ones that I can think of are: * The new semantics blessing for using `define' forms instead of `let' etc makes code easier to read and avoids some right-drift. * There's the need (which I recently talked to at NEU) for some kind of a `define*' form that can be used as a definition with a `let*' scope. For those who weren't there, the summary of the issue is something that Jay once said -- that he sometimes uses (define x0 ...) (define x1 (... x0 ...)) (define x2 (... x1 ...)) because he wants to avoid a `let*'. * The old `scheme/nest' is a direct attempt to prevent drift for some kinds of nestings. * There's the related suggestion for extending the reader with something like `$' or `//' that closes the rest of the sexpr in its own set of parens. * Every once in a while there's a suggestion to invert conversion functions, eg, turn `string-number' into `number-string' so it reads out better. In a similar direction, there are sometimes suggestions to use `compose' to make things more readable, as in ((compose f1 f2 f3 f4) x) vs (f1 (f2 (f3 (f4 x and the textual mess that the latter tends to end up as with real names. * srfi-2 defines an `and-let*' which is addressing a common pattern of interleaving nested `let's and `and's. Actually, `cond' itself is addressing this kind of problem too, so add here various suggestions for extending `cond' with binders, anaphoric forms etc. * Recently, I looked at some clojure pages (to hunt for new extensions to `racket/list'), and I saw that they have a threading form using `-' that expresses nested function calls. See this here: http://clojuredocs.org/clojure_core/clojure.core/-%3E and note also the other three variants, `-' `-?' and `-?', * (The list goes on...) (One common theme in all of these is that they're tools that none of them are tools that are needed -- they're all just ways to make code look better.) I actually started thinking about this when I saw the clojure thing. The first thing that is limited about it is that it has four forms, where the reason for the `-' vs `-' split is to put the nesting in a different argument position. To summarize (and IIUC): (- x (foo 1 2) (bar y)) expands to (bar (foo x 1 2) y) whereas using a `-' would make it expand to (bar y (foo 1 2 x)) Not only does it seem to me bad to have two bindings for this, we also have the usual problem of the order-defying `regexp-replace' where usually the action happens in the *middle* argument... (Which is how it ends up being a common example in showing these problems, as happened recently.) In any case, this looks like an easy thing to fix by adding an explicit marker to the point where the nesting happens. For example, imagine a form that looks like this: (○ x
Re: [racket-dev] Code micro-level organization
On 05/31/2012 02:54 PM, Jay McCarthy wrote: I was clapping through the majority of your email. I want define* so bad. You can use define*; just put it inside of package-begin: (require racket/package) (package-begin (define* x 1) (define* x (+ 2 x)) x) 3 I don't think I like the idea of making the internal definition contexts of racket/base forms act like package-begin, though. Ryan I use compose and curry a lot (even though I know their performance problems) because it don't have to name things. I like the idea of the - thing with the down and up arrows. I see a value in both arrows. I also like Jon's suggestion of a 'last' id... although I'd also want0 throughn or something to refer to so many spots back. Jay On Wed, May 30, 2012 at 3:40 PM, Eli Barzilaye...@barzilay.org wrote: I'm going to ramble a bit about organizing code, trying to look for an idea for a good solution -- so spread a few kgs of salt over the following (if you care to read it). The problem that I'm talking about has several manifestations. The most obvious one is code-drift towards the RHS. A less obvious problem is how it's sometimes hard to read code. To use a cooked up example: (let ([str (string-trim (substring foo bar baz 3 8))]) (and (regexp-match? #rx^[a-z].*[a-z]$ str) (string-append * str *))) to read this, you start from the string literal, then read the `substring' expression, then `string-trim', then the `let' binding, then the `and' and finally the `string-append'[*]. To relate this to the above: besides the right-drift (which is of course very minor here), it takes time to internalize the rules of the language that leads to this, which is a problem for people new to functional programming with it's heavy use of nested function calls. More than that, I think that it's also a problem for *experienced* hackers too -- to see what I mean, open up any random piece of code that deals with an area you're not familiar with, and try to read through it. Personally, I often find myself in such situations reading the actual ordering as I go through the code, and that's fragile since I need to keep mental fingers at various locations in the code in question, sometimes even using my real fingers... You'd probably recognize that there's a whole bunch of tools that are trying to make things better. A few random ones that I can think of are: * The new semantics blessing for using `define' forms instead of `let' etc makes code easier to read and avoids some right-drift. * There's the need (which I recently talked to at NEU) for some kind of a `define*' form that can be used as a definition with a `let*' scope. For those who weren't there, the summary of the issue is something that Jay once said -- that he sometimes uses (define x0 ...) (define x1 (... x0 ...)) (define x2 (... x1 ...)) because he wants to avoid a `let*'. * The old `scheme/nest' is a direct attempt to prevent drift for some kinds of nestings. * There's the related suggestion for extending the reader with something like `$' or `//' that closes the rest of the sexpr in its own set of parens. * Every once in a while there's a suggestion to invert conversion functions, eg, turn `string-number' into `number-string' so it reads out better. In a similar direction, there are sometimes suggestions to use `compose' to make things more readable, as in ((compose f1 f2 f3 f4) x) vs (f1 (f2 (f3 (f4 x and the textual mess that the latter tends to end up as with real names. * srfi-2 defines an `and-let*' which is addressing a common pattern of interleaving nested `let's and `and's. Actually, `cond' itself is addressing this kind of problem too, so add here various suggestions for extending `cond' with binders, anaphoric forms etc. * Recently, I looked at some clojure pages (to hunt for new extensions to `racket/list'), and I saw that they have a threading form using `-' that expresses nested function calls. See this here: http://clojuredocs.org/clojure_core/clojure.core/-%3E and note also the other three variants, `-' `-?' and `-?', * (The list goes on...) (One common theme in all of these is that they're tools that none of them are tools that are needed -- they're all just ways to make code look better.) I actually started thinking about this when I saw the clojure thing. The first thing that is limited about it is that it has four forms, where the reason for the `-' vs `-' split is to put the nesting in a different argument position. To summarize (and IIUC): (- x (foo 1 2) (bar y)) expands to (bar (foo x 1 2) y) whereas using a `-' would make it expand to (bar y (foo 1 2 x)) Not only does it seem to me bad to have two bindings for this, we also have the usual problem of the order-defying `regexp-replace' where usually the action happens in
Re: [racket-dev] Code micro-level organization
I know about package-begin, it's just not worth it if I need to bring in another require and add package-begin Jay On Thu, May 31, 2012 at 3:43 PM, Ryan Culpepper r...@cs.utah.edu wrote: On 05/31/2012 02:54 PM, Jay McCarthy wrote: I was clapping through the majority of your email. I want define* so bad. You can use define*; just put it inside of package-begin: (require racket/package) (package-begin (define* x 1) (define* x (+ 2 x)) x) 3 I don't think I like the idea of making the internal definition contexts of racket/base forms act like package-begin, though. Ryan I use compose and curry a lot (even though I know their performance problems) because it don't have to name things. I like the idea of the - thing with the down and up arrows. I see a value in both arrows. I also like Jon's suggestion of a 'last' id... although I'd also want0 throughn or something to refer to so many spots back. Jay On Wed, May 30, 2012 at 3:40 PM, Eli Barzilaye...@barzilay.org wrote: I'm going to ramble a bit about organizing code, trying to look for an idea for a good solution -- so spread a few kgs of salt over the following (if you care to read it). The problem that I'm talking about has several manifestations. The most obvious one is code-drift towards the RHS. A less obvious problem is how it's sometimes hard to read code. To use a cooked up example: (let ([str (string-trim (substring foo bar baz 3 8))]) (and (regexp-match? #rx^[a-z].*[a-z]$ str) (string-append * str *))) to read this, you start from the string literal, then read the `substring' expression, then `string-trim', then the `let' binding, then the `and' and finally the `string-append'[*]. To relate this to the above: besides the right-drift (which is of course very minor here), it takes time to internalize the rules of the language that leads to this, which is a problem for people new to functional programming with it's heavy use of nested function calls. More than that, I think that it's also a problem for *experienced* hackers too -- to see what I mean, open up any random piece of code that deals with an area you're not familiar with, and try to read through it. Personally, I often find myself in such situations reading the actual ordering as I go through the code, and that's fragile since I need to keep mental fingers at various locations in the code in question, sometimes even using my real fingers... You'd probably recognize that there's a whole bunch of tools that are trying to make things better. A few random ones that I can think of are: * The new semantics blessing for using `define' forms instead of `let' etc makes code easier to read and avoids some right-drift. * There's the need (which I recently talked to at NEU) for some kind of a `define*' form that can be used as a definition with a `let*' scope. For those who weren't there, the summary of the issue is something that Jay once said -- that he sometimes uses (define x0 ...) (define x1 (... x0 ...)) (define x2 (... x1 ...)) because he wants to avoid a `let*'. * The old `scheme/nest' is a direct attempt to prevent drift for some kinds of nestings. * There's the related suggestion for extending the reader with something like `$' or `//' that closes the rest of the sexpr in its own set of parens. * Every once in a while there's a suggestion to invert conversion functions, eg, turn `string-number' into `number-string' so it reads out better. In a similar direction, there are sometimes suggestions to use `compose' to make things more readable, as in ((compose f1 f2 f3 f4) x) vs (f1 (f2 (f3 (f4 x and the textual mess that the latter tends to end up as with real names. * srfi-2 defines an `and-let*' which is addressing a common pattern of interleaving nested `let's and `and's. Actually, `cond' itself is addressing this kind of problem too, so add here various suggestions for extending `cond' with binders, anaphoric forms etc. * Recently, I looked at some clojure pages (to hunt for new extensions to `racket/list'), and I saw that they have a threading form using `-' that expresses nested function calls. See this here: http://clojuredocs.org/clojure_core/clojure.core/-%3E and note also the other three variants, `-' `-?' and `-?', * (The list goes on...) (One common theme in all of these is that they're tools that none of them are tools that are needed -- they're all just ways to make code look better.) I actually started thinking about this when I saw the clojure thing. The first thing that is limited about it is that it has four forms, where the reason for the `-' vs `-' split is to put the nesting in a different argument position. To summarize (and IIUC): (- x (foo 1 2) (bar y)) expands to (bar (foo x 1 2) y)