<div dir="ltr">That's something the JIT should be doing, right?<div><br></div><div>Anyhow, what happens when inlined code throws an error? Which location information is included?</div><div>I'm thinking "if none" then "inline all the funs" away.</div></div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature"><div dir="ltr"><div><div><br></div><div>Cheers,</div><div>-- </div><div>Pierre Fenoll</div></div><div><br></div></div></div></div>
<br><div class="gmail_quote">On 26 November 2015 at 05:52, Richard A. O'Keefe <span dir="ltr"><<a href="mailto:ok@cs.otago.ac.nz" target="_blank">ok@cs.otago.ac.nz</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Summary:<br>
 (1) A promising way to solve the nested updates problem<br>
     is to be more functional, not less.<br>
 (2) There's an approach we could steal from Haskell.<br>
 (3) There's free code to play with, worth every penny.<br>
<br>
Consider a simplified version of Pascal:<br>
<br>
  <variable> ::= <identifier> <selector>*<br>
  <selector> ::= <dereference> | <field> | <index><br>
  <dereference> ::= '^'<br>
  <field> ::= '.' <identifier><br>
  <index> ::= '[' <expression> ']'<br>
<br>
If we think of a selector as a function<br>
  f :: var T1 -> var T2<br>
it's clear that <identifier> <selector> is function<br>
application and <selector 1> <selector 2> is<br>
function composition.<br>
<br>
Yet in Pascal, and C, and languages like them,<br>
while you can *apply* selectors and *compose* them,<br>
they cannot be passed as parameters or even named.<br>
<br>
If a functional language has something like selectors,<br>
they should be first class values, just like other<br>
more-or-less-function-like things.  But what kind of<br>
value?<br>
<br>
I think it was Reynolds, analysing Algol 60, who came<br>
up with the idea that a pass-by-name parameter was<br>
really a *pair* of functions:  one to fetch a value<br>
and one to store it, and thereby freed us from the<br>
limiting idea that there needed to be a 'var T' type.<br>
<br>
The Haskell community have taken this idea and<br>
developed it.  There this concept is called a "Lens".<br>
<br>
<a href="http://www.cs.otago.ac.nz/staffpriv/ok/lens.erl" rel="noreferrer" target="_blank">http://www.cs.otago.ac.nz/staffpriv/ok/lens.erl</a><br>
<br>
is a crude implementation of lenses in Erlang.<br>
A lens is a selector from (values of) type A to<br>
(values of) type B.  It's represented as a triple<br>
<br>
    {Get, Put, Upd}<br>
    Get :: (A) -> B<br>
    Put :: (A, B) -> A<br>
    Upd :: (A, (B) -> B) -> A<br>
<br>
The Get function says how to extract a B value from an<br>
A value.  The Put function says how to put a B value<br>
into an existing A value, returning a new A value.<br>
The Upd function says how to compute a new A value by<br>
extracting a B, applying a function to it, and putting<br>
it back.  We expect the following laws to hold:<br>
<br>
    Get(Put(A, B)) = B<br>
    Put(A, Get(A)) = A<br>
    Upd(A, Fun) = Put(A, Fun(Get(A)))<br>
<br>
That is, if you make a lens by hand, you should ensure<br>
that this is true.<br>
<br>
There are functions for using lenses so you don't have<br>
to think about the representation.<br>
<br>
    lens:get(Lens, A) -> B<br>
    lens:put(Lens, A, B) -> A'<br>
    lens:update(Lens, A, F) -> A'<br>
<br>
There are also functions for making simple lenses.<br>
For example, if you have a record 'rec' with a field<br>
'fld', lens:tuple(#rec.fld) will give you a lens<br>
for that field.<br>
<br>
Warning: the functions in the lens returned by<br>
lens:tuple(#rec.fld)<br>
do NOT check at run time that they are dealing with<br>
a 'rec' record.  They can't, because #rec.fld is just<br>
a number, and you can't get back from that number to<br>
'rec' or the arity of the record.<br>
<br>
The important thing is that these functions compose.<br>
<br>
For example, suppose you have<br>
  -record(foo, {boo,coo,goo,zoo}).<br>
and Foozle is a list of these, and you want to find<br>
the first record with boo=42, and increment its zoo<br>
field by 137.<br>
<br>
    Find = lens:where(fun (#foo{boo=Boo}) -> Boo == 42 end)<br>
<br>
is a lens for finding the record you want and<br>
<br>
    Field = lens:tuple(#foo.zoo)<br>
<br>
is a lens for getting at the zoo field of such a record.<br>
lens.erl provides composition of 2 .. 6 lenses.  So<br>
<br>
    Selector = lens:c(Find, Field)<br>
<br>
is a selector that refers to a field of a record in a list,<br>
and<br>
<br>
    lens:update(Selector, Foozle, fun (Zoo) -> Zoo + 137 end)<br>
<br>
does the whole job (in just one pass through the list, too,<br>
which is why the Upd function is there).<br>
<br>
More simply,<br>
    lens:c(lens:tuple(#a.b), lens:tuple(#c.d),<br>
           lens:tuple(#e.f), lens:tuple(#g.h))<br>
is the equivalent of .b.d.f.h in Pascal, except that it is<br>
a value you can pass around like any other.<br>
<br>
You are not limited to fields that actually exist as such.<br>
For example, you could do<br>
<br>
gb_set(Element) -><br>
    {   fun (Set) -> gb_sets:is_member(Element, Set) end<br>
    ,   fun (Set, false) -> gb_sets:delete_any(Element, Set)<br>
          ; (Set, true)  -> gb_sets:add(Element, Set)<br>
        end<br>
    ,   fun (Set, Fun) -><br>
            Old = gb_sets:is_member(Element, Set),<br>
            case Fun(Old)<br>
              of Old   -> Set<br>
               ; true  -> gb_sets:insert(Element, Set)<br>
               ; false -> gb_sets:delete(Element, Set)<br>
            end<br>
        end<br>
    }.<br>
<br>
and make a gb-set act like a dictionary with Boolean elements.<br>
<br>
There's even a combinator all/1 so that<br>
    All = lens:c(lens:tuple(1)),<br>
    Data = [{3,a},{1,b},{4,c},{6,d}]<br>
    lens:get(All, Data)<br>
 => [3,1,4,6]<br>
    lens:update(All, Data, fun (N) -> N*10 end)<br>
 => [{30,a},{10,b},{40,c},{60,d}]<br>
<br>
So what about cross-module inlining?<br>
<br>
By the time you've made and composed a couple of lenses,<br>
you have a tangle of funs.  If the compiler (a) always<br>
inlines (fun (...) -> ... end)(...) and (b) inlines the<br>
functions from the lens module, then the tangle resolves<br>
tidily into reasonably straightforward code.<br>
<br>
But the cross-module inlining step is crucial.  Without<br>
that, the compiler has nothing to work on.<br>
<br>
At its crudest, consider<br>
<br>
    lens:get(lens:tuple(#rec.fld), Rec)<br>
<br>
*With* cross-module inlining and inlining of funs that<br>
are applied to known arguments and dead code elimination,<br>
you end up with<br>
<br>
    element(#rec.fld, Rec)<br>
<br>
*Without* cross-module inlining, three funs are built,<br>
only one of which will ever be called.<br>
<br>
<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div><br></div>