<div dir="ltr"><div><div><div><div><div><div>I'm slightly late to the lens party but Haskell seems to have a solution to this problem that simultaneously solves another--pattern matching--the location of a value shouldn't be hard-coded similarly in 50 different places that deconstruct a struct just to save typing on an accessor, god forbid the struct change shape or not even be a struct at all anymore.  You want e.g. current-player-health, not the first of the last of the 3rd struct pos of the first.<br>
<br></div>Well with lenses, you can just say<br></div><br><b>currentPlayerHealth = _head . 3rdstructpos . _last . _head</b><br><br></div><div></div>And now you can either set:<br><br><b>set currentPlayerHealth 4 theState</b><br>
<br>or get:<br><br></div><b>view currentPlayerHealth theState</b><br><br>or modify:<br><br></div><b>over currentPlayerHealth (+1) theState</b><br><br></div><div>and other stuff.<br></div><div><br>But these are not macros!  You can thus pass in a lens to determine the 
thing you are setting, e.g. in the game of Dominion you might want to 
move a card from the player's hand to the table or from the hand to 
discards, or from A to B in general.  You can pass in A and B and modify
 those places with real functions.<br><br></div><div>So for Racket, I'm sure everybody who has ever used a mutable struct has had the desire to pass the field name to modify:<br><br></div><div><b>(struct test (x y) #:mutable #:transparent)</b><br>
<br></div><div><b>(define (over <field-name> f a-test)<br></b></div><div><b>  (set-test-<field-name>! a-test (f (test-<field-name> a-test))))</b><br></div><div><br></div><div><b>;example usage<br></b></div>
<div><b>(let ([t (test 1 2)])<br></b></div><div><b>  (over y add1 t))<br></b></div><div><b>=> '(test 1 3)</b><br></div><div><br></div><div>Thanks to people smart enough to understand that a hylomorphism is just an endofunctor in the Hask category of profunctorally-dual product monoids with just a hint of commutative free applicative comonads and a dash of F-algebra, this is possible!<br>
</div><div><br></div>I only found one post in the Racket group on lenses, so I am essentially trying to spread awareness of this, the most powerful thing ever created.  I mean, the type of a lens in Haskell takes 4 parameters.  It has to be good.<br>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Jun 9, 2013 at 6:02 PM, Carl Eastlund <span dir="ltr"><<a href="mailto:cce@ccs.neu.edu" target="_blank">cce@ccs.neu.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr"><div>There are a lot of tradeoffs in decisions like this.  Personally, for instance, I've never found the desire for a generic set!; I just use a specific set! or store a box (mutable reference cell) wherever I need to mutate something.  The impact of an lvalue system is going to be different for each Scheme that implements it.  And no, the impact would probably not be limited to the code that uses mutation.  Features like this usually impose a small cost on everything; having two paths through execution means that every step that doesn't use an lvalue might still be checking "am I using an lvalue now?".  If lvalues mean keeping around references to containers longer than they might be needed, it can have a space impact too -- the feature might delay garbage collection of the container.<br>


<br></div>I don't mean to say this feature might not be useful, and it might be very interesting research to implement it in an existing Scheme.  I just mean it's not immediately obvious that it's a win/win scenario.  Predicting the impact of features like this is difficult, because they're interacting with so much else in the language.<span class="HOEnZb"><font color="#888888"><br>


</font></span><div><div><div class="gmail_extra"><span class="HOEnZb"><font color="#888888"><br clear="all"><div>Carl Eastlund</div></font></span><div><div class="h5">
<br><div class="gmail_quote">On Sun, Jun 9, 2013 at 12:28 PM, Sean Kanaley <span dir="ltr"><<a href="mailto:skanaley@gmail.com" target="_blank">skanaley@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">



  
    
  
  <div bgcolor="#FFFFFF" text="#000000">
    Thanks for the explanation.  I suspected it was for efficiency
    reasons, but as I've never implemented a "real" scheme, I don't know
    the trade off.  I wonder how bad it is.  Way back, they invented
    lisp.  Then they said it was too slow for real stuff.  Now they say
    other languages are too weak for real stuff, and lisp's relatively
    little slowness is made up for by its power.  And here we are,
    saying a powerful feature would slow it down!<br>
    <br>
    Is it 2x, 3x, 4x, 10x, infinityx slower to implement some kind of
    lvalue system?  And wouldn't that system be necessary only in code
    that uses the mutation?<div><div><br>
    <br>
    <div>On 06/09/2013 08:18 AM, Carl Eastlund
      wrote:<br>
    </div>
    <blockquote type="cite">
      <div dir="ltr">
        <div>Sean,<br>
          <br>
        </div>
        Not every Scheme uses an interpreter with an eval function as
        its primary method of execution, or even at all.  Racket uses a
        bytecode interpreter and a JIT native-code compiler; the eval
        function simply triggers compilation to bytecode.  These give a
        great deal more efficiency than running via eval, and supporting
        multiple modes of execution would be significantly more
        expensive.  Evaluating to values by default, rather than to
        addresses, also gives the compiler a great deal of flexibility. 
        It doesn't need to keep track of the addresses where it found
        things and refer to them there in case they are about to be
        mutated; once they have been "found" via evaluation, they can be
        copied to register and the original address can be forgotten, if
        that's most expedient.  I'm not a compiler implementer myself,
        so I'm sure others can probably give more specific details.  In
        the meantime, I hope this explanation is helpful.<br>
        <div class="gmail_extra"><br clear="all">
          <div>Carl Eastlund</div>
          <br>
          <div class="gmail_quote">On Thu, Jun 6, 2013 at 4:12 PM, Sean
            Kanaley <span dir="ltr"><<a href="mailto:skanaley@gmail.com" target="_blank">skanaley@gmail.com</a>></span>
            wrote:<br>
            <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
              <div dir="ltr">
                <div>
                  <div>
                    <div>
                      <div>
                        <div>Hello all,<br>
                          <br>
                        </div>
                        I was curious why Scheme and now Racket does not
                        inherently support a generic set!.  I found an
                        SRFI <a href="http://srfi.schemers.org/srfi-17/srfi-17.html" target="_blank">http://srfi.schemers.org/srfi-17/srfi-17.html</a>
                        that suggests a generic method solution
                        requiring a lookup for the "real" setter (and so
                        needing a special setter for every data type. 
                        What is the disadvantage of simply changing eval
                        to take a "fetch?" parameter that decides
                        whether to ultimately resolve addresses to
                        values?  Then set! is evaluated with this as #f
                        and can operate on whatever that address is.  I
                        have implemented this in a toy interpreter with
                        the bare minimum of forms plus vectors to test. 
                        The vector-ref type of function gets applied as
                        usual to the vector and index arguments, except
                        that if it's within a set! as the left argument
                        where the fetch? is #f and the final fetching of
                        the address given by vector-ref never happens.<br>
                        <br>
                      </div>
                      Here's the critical pieces:<br>
                      <br>
                      <div>1. setting<br>
                      </div>
                      <div>"update" is what changes the store<br>
                      </div>
                      set! is of course a clause within eval<br>
                    </div>
                    <div>the last parameter to eval in the first line
                      says don't fetch<br>
                    </div>
                    <div><br>
                      [(set! addr-x x) (match-let* ([(v*s addr s) (eval
                      addr-x e s #f)]<br>
                                                        [(v*s v s) (eval
                      x e s)])<br>
                                              (update addr v s))]<br>
                      <br>
                      <div>2. evaluating symbols (another clause)<br>
                      </div>
                      <div>the symbol only returns its address with
                        fetching off<br>
                      </div>
                      <div><br>
                        [(sym y) (let* ([addr (lookup y e)]<br>
                                            [val (if fetch? (fetch addr
                        s) addr)])<br>
                                       (v*s val s))]<br>
                      </div>
                      <br>
                    </div>
                    3. the "built-in" (part of environment) vector-ref
                    called vec@<br>
                  </div>
                  "fetch?" will be false if (vec@ ...) is the first
                  argument to set!<br>
                </div>
                "a" is the base address of the vector<br>
                <div>
                  <div><br>
                    <div>
                      <div>(define (vec@-f e s fetch? v i)<br>
                      </div>
                      <div>...unimportant stuff...<br>
                      </div>
                      <div>        (let ([val (if fetch? (fetch (+ a i)
                        s) (+ a i))])<br>
                                  (v*s val s)))))<br>
                        <br>
                      </div>
                      <div>So long as all built-in types have this
                        conditional fetcher, then every user type built
                        on top of them won't need a special setter.  And
                        since this would work just as well for inc!
                        types funtions, from now on<br>
                        <br>
                        (vector-set! v i (add1 (vector-ref v i))<br>
                      </div>
                      <div>is<br>
                      </div>
                      <div>(inc! (vec@ v i))<br>
                      </div>
                      <div><br>
                      </div>
                      <div>I assume this has already been thought of and
                        therefore discarded, but why?<br>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
              <br>
              ____________________<br>
                Racket Users list:<br>
                <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
              <br>
            </blockquote>
          </div>
          <br>
        </div>
      </div>
    </blockquote>
    <br>
  </div></div></div>

</blockquote></div><br></div></div></div></div></div></div>
</blockquote></div><br></div>