mudasobwa

mudasobwa

Creator of Cure

The library to easily map/each/reduce/map_reduce/filter deeply nested maps/keywords/lists, called Iteraptor has been released. Besides standard map-reduce operations, it allows flattening nested terms and deflattening them back, and provides a couple of helper methods for low-level traversing them.

There is a blog post describing the interface in details, and Hexdock.

We were using it in production for months, but since we were not able to catch more bugs on our limited set of nested structures, I would be glad to hear about other use-cases where it fails to traverse the nesteds properly.

Also, it’s extremely handy when one needs to filter out some deeply nested keys, or get just the second level of a nested map, or produce a flattened keyword list out of external config file :slight_smile:

Showing Posts 1 to 8

Qqwy

Qqwy

TypeCheck Core Team

This kind of functionality seems like the perfect fit for Property-based testing :smiley:

gon782

gon782

Indeed, that was my immediate thought as well.

@mudasobwa what is the reasoning behind the names of some of the operations? I would expect each to never return anything, for example, as well as for map to preserve the structure of the thing it’s mapping over. These are standard behaviors connected with the terminology in FP as far as I know and I assume most people familiar with it would expect the same.

mudasobwa

mudasobwa OP

Creator of Cure

I am not sure what did you mean by “map to preserve the structure of the thing it’s mapping over”—mine does to the extent it is able to.

For each we cannot return literally nothing, due to implicit returns in Elixir; the standard Enum.each/2 returns :ok but I found it more convenient to return the input as is (making it easy to inject into |> pipes as IO.inspect e.g. does.

mudasobwa

mudasobwa OP

Creator of Cure

the perfect fit for Property-based testing

Thanks for the suggestion, I’ll do. I am pretty sure though that there is no perfect testing environment where all the issues might be covered, that’s why I kindly asked for bug reports, if any.

gon782

gon782

I mean exactly what I wrote. It’s expected that a map preserves the structure/shape/form of what it’s mapping over. You go against that expectation in your examples, hence my comment about your naming being somewhat odd.

Same goes for each. There is no nothing on the BEAM, so I wouldn’t expect you to return that, but to expect actual output from each is to go against expectation. If someone uses your each as a last expression in a function they won’t get what they were expecting.

I think your library seems good and it’s certainly something that has a use, but your names are not idiomatic. I don’t know if these are Ruby-isms, but I’d argue that you should either change the behavior or the names somewhat to match idiomatic FP.

mudasobwa

mudasobwa OP

Creator of Cure

I never went against that. neither did the code. There is a misunderstanding because this is AFAICT the first implementation of nested term mapping. You have likely mentioned this example:

%{a: %{b: %{c: 42}}}

Please note, that it’s a bare map having the only element in a nutshell. You should not be fooled by the fact that the first value is also a map. So, by what is expected—my map function should return a 1-sized map. That’s it. It does.

Even more, by default (without an explicit option yield: all passed,) the only leaves will be passed to mapper and what you originally expected would happen out of the box (mapper will be called only once with [:a, :b, :c], {:c, 42} as arguments.)

Sometimes, though, one wants to map deeply nested whatever (but not the leaf) to something else. And this library provides such a possibility by accepting yield: all option. This is an extended mode when the library consumer is allowed to map anything on any nesting level. The consistency on each level is still preserved: Enumerable of size N will be mapped to Enumerable of size N.

To make it clear with the aforementioned example:

foo = %{c: 42}
Iteraptor.map(%{a: %{b: foo}}, MAPPER)
#⇒ %{a: %{b: "YAY"}}

Is it looking more familiar now? Well, IMHO yes, because we mapped foo whatever it is to something new. I hope I made the intent/implementation clearer.

Regarding each I plain disagree, sorry for saying that. Since you said “return nothing” in the first place, I treat it as “the caller must not rely on what it returns.” There is no contract on what each should return. And I return the structure itself for easier piping (Erlang does not have pipe operator, that’s why it makes not much sense to return anything but ok atom from erlang mappers, but Elixir indeed does.) I don’t see any violation of expectations here.

gon782

gon782

Naming is about social contracts and both of these functions (and a host of other ones) are associated with certain behaviors in all languages. None of what you’ve explained about your additional behavior changes that. To each his own, though.

mudasobwa

mudasobwa OP

Creator of Cure

Iteraptor gets a new feature in v1.10.1: Iteraptor.jsonify/2 to deeply convert all the Keyword lists to Maps. Jason as well as some other json encoding libraries have issues with marshalling keyword lists, because internal representation of Keyword is eventually a list of tuples, and tuples are not encodeable.

Iteraptor.jsonify/2 traverses the deeply nested term and recursively converts all the keywords to maps.

iex> Iteraptor.jsonify([foo: [bar: [baz: :zoo], boo: 42]], values: true)
#⇒ %{"foo" => %{"bar" => %{"baz" => "zoo"}, "boo" => 42}}
— All posts loaded —

Where Next? Top

Trending in Announcing Top

wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 11030 135
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
fuelen
Hi all! I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas. You...
New
woylie
Phoenix components for pagination, sortable tables and filter forms with Flop and (optionally) Ecto. pagination cursor pagination sorta...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mudasobwa
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews