<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    Hello list,<br>
    <br>
    Partially inspired by jlouis' erl-lenses[1] and an old discussion on
    this mailing list[2], I've been sketching a library for easier
    manipulation (both data fetching and updating) of deep data
    structures (records inside records, keylists inside records, etc.)<br>
    <br>
    I would like to give priority to:<br>
        - Code readability;<br>
        - Safety ('try to crash on unexpected data instead of producing
    hard-to-track misbehaviour';)<br>
        - Reasonable performance (without going the parse-transform
    way.)<br>
    <br>
    Working code already public[3] but it's still a mess and requires
    some cooking before it's ready for human consumption.<br>
    <br>
    What follows is a few statements, also available on Github[4] that
    demonstrate the kind of syntax I am hoping to achieve; input and
    criticism are welcome, as I've been struggling with some design
    decisions and general syntactic coherence.<br>
    <br>
    <br>
    [1]: <a class="moz-txt-link-freetext"
      href="https://github.com/jlouis/erl-lenses">https://github.com/jlouis/erl-lenses</a><br>
    [2]: <a class="moz-txt-link-freetext"
href="http://erlang.org/pipermail/erlang-questions/2013-January/071936.html">http://erlang.org/pipermail/erlang-questions/2013-January/071936.html</a><br>
    [3]:
    <a class="moz-txt-link-freetext"
href="https://github.com/g-andrade/monocle/tree/f1e530f15de5e4aff94dd42bfb2d572afbfc8b96">https://github.com/g-andrade/monocle/tree/f1e530f15de5e4aff94dd42bfb2d572afbfc8b96</a><br>
    [4]:
    <a class="moz-txt-link-freetext"
href="https://github.com/g-andrade/monocle/blob/f1e530f15de5e4aff94dd42bfb2d572afbfc8b96/test/monocle_tests.erl">https://github.com/g-andrade/monocle/blob/f1e530f15de5e4aff94dd42bfb2d572afbfc8b96/test/monocle_tests.erl</a><br>
    <br>
---------------------------------------------------------------------<br>
    <blockquote>-record(phone, {<br>
              operator :: string(),<br>
              number :: string(),<br>
              balance :: float()<br>
      }).<br>
      <br>
      -record(person, {<br>
              name :: string(),<br>
              age :: non_neg_integer(),<br>
              sex :: m | f,<br>
              phone :: #phone{},<br>
              lucky_numbers :: [number()]<br>
      }).<br>
      <br>
      <br>
      tuple_test() -><br>
          Phone1 = #phone{operator = "Telecom",<br>
                          number = "1231234",<br>
                          balance = 23.51},<br>
          Person1 = #person{name = "John Doe",<br>
                            age = 33,<br>
                            sex = m,<br>
                            phone = Phone1,<br>
                            lucky_numbers = [3, 75, 123, 3.2, 74]},<br>
      <br>
          Lens1 = mtuple:get(#person.age),<br>
          EvalA = monocle:eval(Lens1, Person1),<br>
          ?assert(EvalA =:= 33),<br>
          <br>
          Lens2 = mtuple:get(#person.phone, mtuple:get(#phone.number)),<br>
          EvalB = monocle:eval(Lens2, Person1),<br>
          ?assert(EvalB =:= Phone1#phone.number),<br>
      <br>
          Lens3 = mtuple:get(#person.phone, mtuple:get(#phone.balance)),<br>
          EvalC = monocle:eval(Lens3, Person1),<br>
          ?assert(EvalC =:= Phone1#phone.balance),<br>
      <br>
          Lens4 = mtuple:set(#person.phone, <br>
                             mql:fold([mtuple:set(#phone.balance,
      mnum:sub(1)),<br>
                                       mtuple:set(#phone.balance,
      mnum:mul(3)),<br>
                                       mtuple:set(#phone.balance,
      mnum:'/'(3.0)),<br>
                                       mtuple:set(#phone.balance,
      mql:fold([mnum:min(infinity), <br>
                                                                           

      mnum:max(0),<br>
                                                                           

      mnum:mul(-1),<br>
                                                                           

      mnum:mul(-1)])),<br>
                                       mtuple:set(#phone.balance,
      mnum:sub(1 bsl 3)),<br>
                                       mtuple:set(#phone.balance,
      mnum:add(1 bsl 3))])),<br>
          EvalD1 = monocle:eval(Lens4, Person1),<br>
          EvalD2 = monocle:eval(Lens3, EvalD1),<br>
          ?assert(EvalD2 =:= Phone1#phone.balance - 1),<br>
      <br>
          Lens5 = mtuple:get(#person.lucky_numbers, mlists:sum()),<br>
          EvalE = monocle:eval(Lens5, Person1),<br>
          ?assert(EvalE =:= lists:sum(Person1#person.lucky_numbers)),<br>
      <br>
          Lens6 = mql:map([mtuple:get(#person.name),<br>
                           mtuple:get(#person.age),<br>
                           mtuple:get(#person.phone,
      mtuple:get(#phone.number))]),<br>
          EvalF = monocle:eval(Lens6, Person1),<br>
          ?assert(EvalF =:= [Person1#person.name,<br>
                             Person1#person.age,<br>
                             Phone1#phone.number]),<br>
      <br>
          ok.<br>
    </blockquote>
    <br>
    <pre class="moz-signature" cols="72">-- 
Guilherme

<a class="moz-txt-link-freetext" href="https://www.gandrade.net/">https://www.gandrade.net/</a>
PGP: 0x602B2AD8 / B348 C976 CCE1 A02A 017E 4649 7A6E B621 602B 2AD8
</pre>
  </body>
</html>