Nm - a tool to work with deeply nested data structures

I’ve just publish something I’ve been experimenting with:

Hex

nm

nm is a library to help manipulate and transform deeply nested data structures in a simple way.

Since the discussion about local accumulators I’ve joined some discussions on ways to deal with it properly.
I’ve always argued that this is difficult and yes, it should be difficult, you’re trying to change a deeply nested tree of data and you’re trying to apply mutability adhoc to a immutable data structure. Thinking on ways to handle that more easily I’ve always come to the conclusion that the “simple”(not the best and not the fastest) is just to unnest that tree into a more “linear” structure. That’s where the starting point for nm.

It has some limitations, it only consider “nesteable data structures” as lists and maps, so keywordlists, tuples and other data types will not be “unnested”.
This is very early work, i’ve just come with the most simple and basic api that can be useful and somewhat easy to use. I’ve been thinking to improve that api with something close to the Access behavior(from elixir, the idea is to have a common vocabulary on manipulating data), but first I gonna improve documentation and provide some examples(I’m planning to do an example in elixir and erlang for doing the problem that Valim shows in the local accumulators repository).

I’d like to receive some feedback and opinions on this type of library if it makes sense and all that. If you could just apply it to your most nasty deeply nested structures and see if it’s useful, i’d be thankful. :slight_smile:

2 Likes

Also I made this example using the library for the problem statement that Valim did in the local accumators thread in the elixir forum.

-module(traversal).

-export([traverse/1]).

traverse(Data) ->
    {ok, Table} = nm:unnest(Data),
    {ok, Root} = nm:get_value(Table, root),
    lists:foldl(fun root_traversal/2, {Table, 1, 1}, Root),
    nm:nest(Table).

root_traversal({'$nm_ref', Id}, {Table, C10, C20}) ->
    {ok, Current} = nm:get_value(Table, Id),
    {'$nm_ref', ListId} = maps:get(<<"lessons">>, Current),
    {ok, Lessons} = nm:get_value(Table, ListId),
    Updated = maps:put(<<"position">>, C10, Current),
    nm:fast_update(Table, Id, Updated),
    C21 =
        case maps:get(<<"reset_lesson_position">>, Current) of
            true -> 1;
            false -> C20
        end,
    {_, C22} = lists:foldl(fun lessons_traversal/2, {Table, C21}, Lessons),
    {Table, C10 + 1, C22}.

lessons_traversal({'$nm_ref', Id}, {Table, C0}) ->
    {ok, Current} = nm:get_value(Table, Id),
    Updated = maps:put(<<"position">>, C0, Current),
    nm:fast_update(Table, Id, Updated),
    {Table, C0 + 1}.

I may have missed it, but is nm short for “nested manipulation”? I was initially confused since nm is an existing tool for listing symbols from object files. I thought this might’ve been a blob inspector or something :slight_smile:

yep, that was the idea.

1 Like