[racket] Size matters

From: Sean Kanaley (skanaley at gmail.com)
Date: Sun Jun 9 11:50:20 EDT 2013

The idea was to provide an extended name for free, so I should've used 
named let.  Named functions of course already have names, e.g.

(define (z x)
   (let q ([x #1])
     (let ([x #2])
     (+ z:x q:x x)

Plain "let" evaluates in parallel, so in (let ([x y] [x x]) the last x 
is free.  So qualifying like ([x:n is inconsistently naming part of a 
scope, the part pertaining to a single variable, and so it's actually 
just renaming the variable itself.  The qualifier should extend to the 
entire "frame" or whatever it's called for the things it's qualifying.  
Although your code would be perfect for the nested let, "let*".

On 06/09/2013 03:03 AM, ??????? ????? wrote:
> Then why not
> (let ([x:n #1])
>   (let ([n #2])
>     (+ x:n n)
>
> I think, it is less confusing
>
>
> ???????, 8 ???? 2013, 17:07 -04:00 ?? Sean Kanaley <skanaley at gmail.com>:
>
>     Sorry about the multiple posts, but an idea just occurred to me to
>     save on name length in the case of name conflicts, like in the
>     posted fill-sack example.  Example code:
>
>     (let ([n #1])
>       (let ([n-that-needs-new-name #2])
>         (+ n n-that...)
>
>     The inner most n will overwrite the outer one if the same name is
>     used, but sometimes, logically, the same name /should/ be used. 
>     There's two "n"s at work, and it's the entire point of lexical
>     scope to provide the proper one.  So there should be a mechanism
>     to access a different one.  Behold:
>
>     (let (x [n #1])
>       (let ([n #2])
>         (+ x:n n)
>
>     On 06/08/2013 03:49 PM, Eli Barzilay wrote:
>>     (Possible irrelevant rambling, but I generally am very aware of my
>>     code formatting, and this looked like a good point to highlight.  It's
>>     still probably picking on something that not many people care about as
>>     much as I do...)
>>
>>     The style guide has a section labeled "size matters" -- it also has
>>     another section on names, encouraging using readable names.  Both of
>>     these are perfectly reasonable goals, but they can pull you in
>>     different directions, and I ran into an example that demonstrates it
>>     in a very nice way.  There is also Yaron's quote about favoring
>>     readers, which is IMO more important than both of these -- since they
>>     are just sub-points aiming towards that goal.
>>
>>     I have recently experimented more with taking code compactness more
>>     seriously.  I still keep my own code under 80 characters, which I know
>>     many people don't like, but on the other hand, I always try to fill
>>     the lines as much as possible while maintaining readability.  The idea
>>     is that the principle of favoring readers means that it should be easy
>>     to read code -- and lines that are too long, or suffer from rightward
>>     drift, or names that are too long are all things that delay reading.
>>     I can also see the recent tendency to use `define' where possible as
>>     something that goes to this end too: prefer using the same kind of
>>     binding construct to make it easier to read code.
>>
>>     So to get to my point, there's the decision of what name to use for
>>     your identifiers some people (*ahem*) stick to an always-readable
>>     names, to the point of not using names like `i', `n', and `x'.  I'm on
>>     the complete other side of this -- I strongly prefer these names
>>     because they make code shorted and therefore easier to read.  The same
>>     goes for the style guide's recommendation to name intermediate values
>>     instead of nesting function calls -- it's obviously a line that the
>>     author should decide on (exaggerated examples on both sides are easy,
>>     and contribute nothing), and I tend to go further with nested calls
>>     than defining intermediates.  (This same point applies to naming
>>     functions vs using lambda expressions.)
>>
>>     My point here is that using longer names and binding intermediates can
>>     explain the code better, but it's easy to carry this over to hurting
>>     overall readability.  The example that made me post this is below (no
>>     need to look up who wrote the original code, it's irrelevant since it
>>     *is* following many of the style's guidelines).  The first chunk is
>>     the original code, the second is my rewrite.  There are some obvious
>>     things like using `match' to make the code more concise and more
>>     readable, but note that the `cond' expression in the loop is very hard
>>     to read in the first version -- the descriptive names are long enough
>>     that the overall structure of the loop is not obvious.
>>
>>     In my revision, the much shorter names are less readable, but on the
>>     flip side they allow laying out the code in a way that makes it much
>>     more obvious, and since I started this by just doing mechanical
>>     transformations, it was surprising to see that what the shrunk code is
>>     doing becomes very clear.  This clarity has the obvious advantages,
>>     which is why it's so important to "favor readers".
>>
>>     As a sidenote -- there are two named intermediates in this code that I
>>     didn't get rid of: on one hand losing them won't save space (and
>>     therefore I consider removing them as something that would only
>>     obfuscate things), and on the other hand the result would be nesting
>>     the verbose computation into a place where it is not relevant.  (And
>>     yes, there'd be an advantage for having an infix syntax here, IMO...)
>>
>>     (In any case, sorry for the noise.  I'll avoid further replies...)
>>
>>     -------------------------------------------------------------------------------
>>
>>     (define (fill-sack (items items) (volume-left 0.25) (weight-left 25) (sack null) (sack-value 0))
>>        (if (null? items)
>>            (values (list sack) sack-value)
>>            (let* ((item (first items))
>>                   (item-wgt (item-weight item))
>>                   (max-q-wgt (floor (/ weight-left item-wgt)))
>>                   (item-vol (item-volume item))
>>                   (max-q-vol (floor (/ volume-left item-vol))))
>>              (for/fold
>>                  ((best-sacks (list sack))
>>                   (best-sack-value sack-value))
>>                ((qty (in-range 0 (add1 (min max-q-vol max-q-wgt)))))
>>                (let-values (((inner-best-sacks inner-best-sack-value)
>>                              (fill-sack (cdr items)
>>                                         (- volume-left (* qty item-vol))
>>                                         (- weight-left (* qty item-wgt))
>>                                         (cons (cons qty item) sack)
>>                                         (+ sack-value (* qty (item-value item))))))
>>                  (cond
>>                    [(> inner-best-sack-value best-sack-value)
>>                     (values inner-best-sacks inner-best-sack-value)]
>>                    [(= inner-best-sack-value best-sack-value)
>>                     (values (append best-sacks inner-best-sacks) inner-best-sack-value)]
>>                    [else (values best-sacks best-sack-value)]))))))
>>
>>     -------------------------------------------------------------------------------
>>
>>     (define (fill-sack items volume-left weight-left sack sack-value)
>>        (match items
>>          ['() (values (list sack) sack-value)]
>>          [(cons (and (item _ _ item-val weight volume) item) items)
>>           (define max-q-wgt (floor (/ weight-left weight)))
>>           (define max-q-vol (floor (/ volume-left volume)))
>>           (for/fold ([best (list sack)] [best-val sack-value])
>>                     ([n (exact-round (add1 (min max-q-vol max-q-wgt)))])
>>             (define-values [best* best-val*]
>>               (fill-sack items
>>                          (- volume-left (* n volume))
>>                          (- weight-left (* n weight))
>>                          (cons (cons n item) sack)
>>                          (+ sack-value (* n item-val))))
>>             (cond [(> best-val* best-val) (values best* best-val*)]
>>                   [(= best-val* best-val) (values (append best best*) best-val*)]
>>                   [else                   (values best best-val)]))]))
>>
>>     -------------------------------------------------------------------------------
>>
>
>     ____________________
>       Racket Users list:
>     http://lists.racket-lang.org/users
>
>
>
> -- 
> ????? ???????
>
>
> ____________________
>    Racket Users list:
>    http://lists.racket-lang.org/users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130609/5b045b95/attachment.html>

Posted on the users mailing list.