<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>