Re: [racket-dev] Code micro-level organization

2012-06-01 Thread Eli Barzilay
[Combined reply]

Two days ago, Jon Rafkind wrote:
> On 05/30/2012 04:07 PM, Eli Barzilay wrote:
> >
> >> Having expressions come from the bottom, using the down arrow, seems
> >> sort of wierd.
> > Here's a concrete example:
> >
> >   (○ (let ([x 10]) ↓)
> >  (for ([i (in-range x)]) ↓)
> >  (for ([j (in-range i)]) ↓)
> >  ...etc...)
> >
> > Do you have a concrete suggestion for doing that?
> 
> Well in this case its easy, just remove the closing ) from each of
> the lines so the next line is nested in the right place.

Yes, but then you get the drift which is one of the things that it's
trying to eliminate.  (It's true that strictly speaking you don't need
that -- but the premise of this whole thing is a tool for structuring
code for easier reading & writing, like many other unnecessary tools
(which are most of the language, of course).)


> If you were going to use the down arrow in a different position,
> like
> 
> (for ([i ↓]) ..blah..)
> (let ...)
> 
> I think things would get out of hand quickly because the physical
> gap between the for expression and the let expression could get
> quite large.

The use case for these things would be to simplify the code in a way
that puts each "point of focus" on consecutive lines.  To demonstrate
with just the above, you *could* do something like this:

  ;; print a table of square roots
  (○ (for ([i ↓]) (printf "~s² = ~s\n" (* i i)))
 (in-range 0 100))

But that doesn't make much sense, since using the range expression
inside the for loop is more readable.  This is not different from this
weird way to write this code:

  (let ([f (λ (x) (for ([i ↓]) (printf "~s² = ~s\n" (* i i])
(f (in-range 0 100)))

Cases where you would use that is when that expression is that main
focus of the code, for example

  (○ (for/list ([i ↓]) (* i i))
 (in-sequences ↓ (in-range 10))
 (stop-after ↓ zero?)
 (in-naturals ↓)
 (fib 10))


> I mean I hope I'm not trivializing your issue, do you have a
> different example?

Any example where that main focus is not the last expression, like the
above.  Here's a different one:

  (○ (for ([i 10]) ↓ (newline))
 (for ([j 10]) ↓)
 (printf " ~s" (* i j)))


Yesterday, Neil Toronto wrote:
> 
> It seems like `↑' is another way to not name expressions (i.e. a
> "pointless style" :D),

(I can't parse that.)


> 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 "*"))

Yes, I mentioned this hack explicitly.  Maybe it will help if I
clarify why it's a hack: it forces you to choose names where you don't
need any.  For example, see how the names you chose are bad?  -- `str'
doesn't make sense in such a line, so it would become something like
`trimmed-string', and `m' is a buggy convention since it's usually
used with the results of matching so it should be something like
`is-word?'.  And now names are repeating information that is already
clearly visible in the code, which makes me dislike it even more than
the hugarian naming convention.

Another way to deal with this is with a generic base for the name
(which is what I remember Jay posting at some point), as in

  (define x1 ...)
  (define x2 ...)
  ...

This is also a pretty bad way to do that, since the names are
meaningless labels so the machine should be dealing with them, not me.
(Note in particular how adding new intermediate expressions requires
shifting names -- in a way that can eventually lead to a convention of
`x10', `x20', etc so it's easier to debug...)

But a more high-level point is that I *am* already using a highlevel
language where names are not always necessary, and I'd like to keep
that freedom without sacrificing code readability.  The argument that
is usually made for your example is "I find that being forced to use
descriptive names help" -- that can obviously be true in some cases,
but I dislike requiring it.  A technical problem with this argument is
that it omits the fact that you really need *unique* names; the
high-level problem with the argument is that it's *exactly* the same
argument that people have been using for ages as an excuse to not
having some kind of `lambda' in their languages.


> A `define*' form like Jay (and I) want would make these kinds of
> things less error-prone and allow names to be reused:
> [...]

Right, and it looks like there's strong opposition to that, which is
why I'm trying to find something that can be done.  What I'm
suggesting is not a complete replacement -- one thing it doesn't do is
use different names for farther references (and that's why I asked for
examples), and another difference is that I'm talking about a macro so
you won't be able to use more than one `↑' (or whatever is a good name
for

Re: [racket-dev] Code micro-level organization

2012-05-31 Thread Jay McCarthy
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  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 want<0>  through  or something to refer to so
>> many spots back.
>>
>> Jay
>>
>> On Wed, May 30, 2012 at 3:40 PM, Eli Barzilay  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

Re: [racket-dev] Code micro-level organization

2012-05-31 Thread Ryan Culpepper

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 want<0>  through  or something to refer to so
many spots back.

Jay

On Wed, May 30, 2012 at 3:40 PM, Eli Barzilay  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 ac

Re: [racket-dev] Code micro-level organization

2012-05-31 Thread Jay McCarthy
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  or something to refer to so
many spots back.

Jay

On Wed, May 30, 2012 at 3:40 PM, Eli Barzilay  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
> ex

Re: [racket-dev] Code micro-level organization

2012-05-31 Thread Laurent
(sorry for the bad indentation, writing s-exps on a phone predictive
keyboard is painful...)
Le 31 mai 2012 19:21, "Laurent"  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"  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

2012-05-31 Thread Laurent
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"  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

2012-05-31 Thread Neil Toronto

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

2012-05-30 Thread Jon Rafkind
On 05/30/2012 04:07 PM, Eli Barzilay wrote:
>
>> Having expressions come from the bottom, using the down arrow, seems
>> sort of wierd.
> Here's a concrete example:
>
>   (○ (let ([x 10]) ↓)
>  (for ([i (in-range x)]) ↓)
>  (for ([j (in-range i)]) ↓)
>  ...etc...)
>
> Do you have a concrete suggestion for doing that?
>

Well in this case its easy, just remove the closing ) from each of the lines so 
the next line is nested in the right place. If you were going to use the down 
arrow in a different position, like

(for ([i ↓]) ..blah..)
(let ...)

I think things would get out of hand quickly because the physical gap between 
the for expression and the let expression could get quite large.

I mean I hope I'm not trivializing your issue, do you have a different example?
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] Code micro-level organization

2012-05-30 Thread Eli Barzilay
A few minutes ago, Jon Rafkind wrote:
> 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".  The
> > thing that makes me excited about this is how you can read this as the 
> > above [*] reading.
> 
> Maybe a simpler proposal is just a 'last' identifier that is always
> bound to the previous expression?

That's basically the (improved) thing that you get in clojure, and the
problem is that it doesn't fit nesting in the other way, which is what
`nest' does.  Something that I forgot to fill in the previous post is
that this could be one reason why they have the `-?>' and `-?>>'
forms: these things are dealing with conditional values, which is
something that you get with nesting that goes in the other direction.

(As for the identifier names, I think of them as "the above" and "the
below", so maybe those are better names.)


> Having expressions come from the bottom, using the down arrow, seems
> sort of wierd.

Here's a concrete example:

  (○ (let ([x 10]) ↓)
 (for ([i (in-range x)]) ↓)
 (for ([j (in-range i)]) ↓)
 ...etc...)

Do you have a concrete suggestion for doing that?

-- 
  ((lambda (x) (x x)) (lambda (x) (x x)))  Eli Barzilay:
http://barzilay.org/   Maze is Life!

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] Code micro-level organization

2012-05-30 Thread Jon Rafkind
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".  The
> thing that makes me excited about this is how you can read this as the 
> above [*] reading.

Maybe a simpler proposal is just a 'last' identifier that is always bound to 
the previous expression? I think having two arrows could get confusing. I'm not 
really a fan of the `let' expression binding `str' in the scope of all the 
expressions below it since they only occur in the `let' due to the down arrow.

But with "last" it would be:

  (* "foo bar baz"
  (substring last 3 8)
  (string-trim last)
  (let ([str last])
 (* (string-append "*" str "*"))
 (and (regexp-match ... str) last)))

Having expressions come from the bottom, using the down arrow, seems sort of 
wierd.
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


[racket-dev] Code micro-level organization

2012-05-30 Thread Eli Barzilay
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
 (foo 1 <> 2)
 (bar y <>))

that expands to (bar y (foo 1 x 2)).  (The reason that clojure has two
other forms (`-?>' and `-?>>') is something that is related to the
below, so I'll skip it for now.)

The next thing that I tried is to contrast this with `nest'.  The
difference between them is that while both lead to a simpler syntax
for nested expressions, they do the nesting in different directions,
where (*very* roughly speaking) `->' nests things downwards and `nest'
nests them upwards: