[erlang-questions] Deep data structures and lenses
Guilherme Andrade
g@REDACTED
Sat Sep 12 19:51:39 CEST 2015
Hello list,
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.)
I would like to give priority to:
- Code readability;
- Safety ('try to crash on unexpected data instead of producing
hard-to-track misbehaviour';)
- Reasonable performance (without going the parse-transform way.)
Working code already public[3] but it's still a mess and requires some
cooking before it's ready for human consumption.
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.
[1]: https://github.com/jlouis/erl-lenses
[2]: http://erlang.org/pipermail/erlang-questions/2013-January/071936.html
[3]:
https://github.com/g-andrade/monocle/tree/f1e530f15de5e4aff94dd42bfb2d572afbfc8b96
[4]:
https://github.com/g-andrade/monocle/blob/f1e530f15de5e4aff94dd42bfb2d572afbfc8b96/test/monocle_tests.erl
---------------------------------------------------------------------
-record(phone, {
operator :: string(),
number :: string(),
balance :: float()
}).
-record(person, {
name :: string(),
age :: non_neg_integer(),
sex :: m | f,
phone :: #phone{},
lucky_numbers :: [number()]
}).
tuple_test() ->
Phone1 = #phone{operator = "Telecom",
number = "1231234",
balance = 23.51},
Person1 = #person{name = "John Doe",
age = 33,
sex = m,
phone = Phone1,
lucky_numbers = [3, 75, 123, 3.2, 74]},
Lens1 = mtuple:get(#person.age),
EvalA = monocle:eval(Lens1, Person1),
?assert(EvalA =:= 33),
Lens2 = mtuple:get(#person.phone, mtuple:get(#phone.number)),
EvalB = monocle:eval(Lens2, Person1),
?assert(EvalB =:= Phone1#phone.number),
Lens3 = mtuple:get(#person.phone, mtuple:get(#phone.balance)),
EvalC = monocle:eval(Lens3, Person1),
?assert(EvalC =:= Phone1#phone.balance),
Lens4 = mtuple:set(#person.phone,
mql:fold([mtuple:set(#phone.balance,
mnum:sub(1)),
mtuple:set(#phone.balance,
mnum:mul(3)),
mtuple:set(#phone.balance,
mnum:'/'(3.0)),
mtuple:set(#phone.balance,
mql:fold([mnum:min(infinity),
mnum:max(0),
mnum:mul(-1),
mnum:mul(-1)])),
mtuple:set(#phone.balance,
mnum:sub(1 bsl 3)),
mtuple:set(#phone.balance,
mnum:add(1 bsl 3))])),
EvalD1 = monocle:eval(Lens4, Person1),
EvalD2 = monocle:eval(Lens3, EvalD1),
?assert(EvalD2 =:= Phone1#phone.balance - 1),
Lens5 = mtuple:get(#person.lucky_numbers, mlists:sum()),
EvalE = monocle:eval(Lens5, Person1),
?assert(EvalE =:= lists:sum(Person1#person.lucky_numbers)),
Lens6 = mql:map([mtuple:get(#person.name),
mtuple:get(#person.age),
mtuple:get(#person.phone,
mtuple:get(#phone.number))]),
EvalF = monocle:eval(Lens6, Person1),
?assert(EvalF =:= [Person1#person.name,
Person1#person.age,
Phone1#phone.number]),
ok.
--
Guilherme
https://www.gandrade.net/
PGP: 0x602B2AD8 / B348 C976 CCE1 A02A 017E 4649 7A6E B621 602B 2AD8
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20150912/a066cc7b/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: OpenPGP digital signature
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20150912/a066cc7b/attachment.bin>
More information about the erlang-questions
mailing list