[erlang-questions] If you are homesick for object.selector

Fred Hebert <>
Fri Jan 25 17:55:06 CET 2013


On 01/25, Lo?c Hoguin wrote:
> *Data*. Not code. Access. Update. That's all that's needed.

Alright, here's a 15 minutes attempt at getting some monster design
working based on tuple lists, but any data structure that's dynamic
enough (not records) would probably do. No benchmarking, no testing,
but you can pretty much use lists of accessors in verbose manner, but
less verbose than your usual dictionary or k/v use.

Here's how the code is used (I used terrible function names on
purpose!):

    test() ->
        %% build
        Char1 = '='('='('='('='('0'(),
                    [name], karl),
                    [current,weapon,points], 10),
                    [current,weapon,name], "crappy sword"),
                    [stats, level], 3),
        Skills = '='('='('='('0'(),
                     [strength], 12),
                     [charisma], 7),
                     [luck], 3),
        Char = '='(Char1, [stats,skills], Skills),
········
        %% read
        [{strength, '?'(Char, [stats,skills,strength])},
         {item, {'?'(Char, [current,weapon,name]),
                 '?'(Char, [current,weapon,points])}},
         {damage, '?'(Char, [current,weapon,points]) *
                  '?'(Char, [stats,skills,strength]) +
                  '?'(Skills, [luck])}
        ].

'='/3 sets fields, '?'/2 reads from them. Note that you
can either build everything from the top level (Like 'Char1' does)
or do it in incremental steps (the way 'Skills' is done). Fetching
respects the same concept.

And here's the output:

    1> hubble:test().
    [{strength,12},
     {item,{"crappy sword",10}},
     {damage,123}]

That seems to work. And here's the code

    -module(hubble).
    -export(['0'/0, '='/3, '?'/2]).
    -export([test/0]).
····
    '0'() -> [].
····
    '='(L, Fields, Val) ->
        set(L, Fields, Val).
····
    '?'(L, Fields) ->
        fetch(L, Fields).
····
    set([], [K], V) ->
        [{K,V}];
    set(L, [K], V) ->
        lists:keystore(K, 1, L, {K,V});
    set(L, [K|T], V) ->
        case lists:keyfind(K, 1, L) of
            false ->
                lists:keystore(K, 1, L, {K, set([], T, V)});
            {K,Old} ->
                lists:keyreplace(K, 1, L, {K, set(Old, T, V)})
        end.
····
    fetch(L, [K]) ->
        case lists:keyfind(K, 1, L) of
            false -> undefined;
            {K,V} -> V
        end;
    fetch(L, [H|T]) ->
        {H, L2} = lists:keyfind(H, 1, L),
        fetch(L2,T).

Basic list functionality with a tiny wrapper, no parse
transform, usable as a library over any k/v data type today.

There's probably a connection to be made to jlouis' lenses in
how this is organized.

I'm guessing someone with more than 15 minutes could probably
make a decent parse transform out of it, overload some syntax
or whatever and get it to a more usable/pretty level. The mechanism
seems to generaly work, though.

Regards,
Fred.



More information about the erlang-questions mailing list