Qqwy

Qqwy

TypeCheck Core Team

tl;dr: I challenge you: let us implement containers for Elixir, and use this topic to coordinate the effort.


Hello, dear fellow Elixir developers.

Recently, multiple discussions (like this and this) have popped up about ‘Elixir not having a built-in data type XXX’.

While for some part we can rely on things that are already part of Erlang (such as :queue or :array), there are of course drawbacks to using Erlang modules:

  1. No Protocol support.
  2. No documentation (that is part of IEx).
  3. No introspection, as they do not work on structs (structs are, after all, an Elixir invention).
  4. Most of these libraries were made before Maps were a thing (Maps were introduced in OTP 17), and using maps we might create more efficient data structures (in space/time) in some cases.

On the other hand, the Elixir standard library only contains the container types Lists, Maps, and MapSets (and Range, but it is clearly the ‘odd one out’). It definitely is not the role of the Elixir standard library to provide built-in datatypes for everything, however. That is something where FOSS libraries can shine.

I myself have until now built Tensor, which introduces sparse vectors, matrices and n-dimensional tensors (collections that allow for amortized constant-time element access/update as they are built on top of maps).
I am currently in the process of creating Okasaki, which is a library containing multiple different versions of Queues and Deques (double-ended queues) with different time/memory properties.


One thing I realized, which is partly why I am starting this topic, is that the Enum and the Enumerable protocol will throw away the structure of the container you had, always returning lists as result.
I therefore am going to implement a common interface, based on the actual properties that are required to perform certain operations.

I challenge you to start implementing container data structures and release them as FOSS libraries. I think it would be wonderful to start a semi-coordinated effort through this forum, to ensure that Elixir gets a nice zoo of data structures that can be used to solve a wide variety of problems.


Suggested Container datatypes (And what libraries are working on them)

(feel free to suggest one)

  • Trees: (Many other container types can be built on top of trees)
    • Binary trees
    • Red-Black trees
    • Rose trees
    • 2-3 finger trees
    • Patricia trees
  • Queues: Okasaki tries to implement multiple variants of these.
    • FIFO Queues
    • LIFO Stacks (List covers this somewhat, but maybe there are other ways to implement stacks with different guarantees as well? (And then have a unified interface for any kind of stack-like implementation? :heart_exclamation:)
    • Deques (Double-Ended Queues)
  • Priority Queues Prioqueue
  • Heaps
  • Sets: Implemented in Sets
    • HashSet (Builtin)
    • Tree-based Set
  • Multisets and Bags
  • Fast Random-Access Sequences
    • Arrays implements some of these:
      • MapArray
      • :array (heap-based array)
    • Something akin to Haskell’s Data.Sequence that allows O(1) access to both extremes of the container.
    • Immutable arrays (á la Haskell IArray? or Erlang’s :array?)
    • Someting working with DiffArrays?
  • Sparse Vectors/Matrices/Tensors: Tensor
  • Graphs
    • Adjacency list
    • Adjacency matrix
    • Incidency matrix.

Showing Posts 35 to 26

Qqwy

Qqwy OP

TypeCheck Core Team

Yes, although there is also something to be said for keeping each of the packages small (only containing the public API and one or two default implementations), with a bunch of other implementation packages to be used when more efficiency or other functionality is required.

daveman1010220

daveman1010220

If this will not be part of the standard library some day, it would be excellent to have all of these containers in one package. If you have one package that supports a large set of standard data structures then it will be much easier for someone working on a BLAS library to make use of it. Having just a couple of well-thought-out packages that contain most basic data structures and the most common math functions would be tremendously useful, in my opinion. You can then tell people, “Just use the math and containers packages”…

Qqwy

Qqwy OP

TypeCheck Core Team

Okasaki has received an overhaul and is now released as v1.0!

Changes are:

  • Everything is now documented! :sunglasses:
  • ErlangQueue and ErlangDeque implementations that wrap :queue.
  • Implementing FunLand.Mappable for the queues and deques.
  • More tests!
OvermindDL1

OvermindDL1

That would be nice, but if doing that I’d link to a BLAS-like library instead (think NumPy for Python, but for Erlang). That way you can built up a set of instructions (macro?) that is sent to the BLAS engine to process potentially huge amounts of data at once then return the result (probably not explicitly returned either but rather as a BEAM resource ID so you can use the API to pull out bits of it or to an erlang format but keeping the base of it as highly optimized as possible, again similar to how Python does it).

With the new async: on option by default in OTP20 this would fit that use-case so well, and I would definitely use such a library. Honestly I really would build it on top of a BLAS library (one that does not crash please if you link it as a NIF or so).

Also, you’ve been busy! ^.^

Qqwy

Qqwy OP

TypeCheck Core Team

Inspired by the earlier discussion with @rvirding, I am currently creating a library, Iter, that allows to iterate over arbitrary data structures in a possibly non-destructive way.

That is, where Extractable.extract will extract an item and return a collection with that item removed, Iter.next() will return the next item and a collection that might or might not be altered.

This means that Iterator structs wrapping things like ETS tables, :gb_sets and :gb_trees can be made as well.

There are two kinds of Iterators inside Iter:

  • ‘Normal’ iterators which might convert the thing they iterate on to a structure more appropriate for iteration. (This is used for many datatypes that right now do not have built-in first/1, next/2-support; they are frequently changed into lists)
  • and ‘Persistent’ iterators which are guaranteed to be able to reconstruct the thing they iterate over at the end.

Note that the functionality of a PersistentIterator is a superset of a normal Iterator, possibly at the cost of some time and memory efficiency.

I am not yet sure what (if any) advantage a PersistentIterator has over a non-persistent iterator, as we usually still have access to the original data structure before it was turned into an iterator.

But I wanted to build it, in part because I thought of a fun way to (ab)use improper lists to reverse-concatenate two lists (restoring a zipper back to its original list): elixir-iter/lib/iter/implementations/list.ex at master · Qqwy/elixir-iter · GitHub

And in part because there very well might be a proper use for them.

Because these Iterators only iterate on-demand, they are per definition lazy.
I am going to think about what would be the best way to create higher-order iterators (‘iteratees’ or ‘iterator adaptors’), and how the efficiency of the thing could be improved.

This style of iterating is based on the ‘Iteratee’ concept used in Haskell, and also the Iterators in Rust. (Rusts’ iterators work with owned, mutable data however, and therefore are both faster and guaranteed to extract items returned by the iteration from their containers; two guarantees Iter cannot give you).

Qqwy

Qqwy OP

TypeCheck Core Team

And just after I said that, I decided to finish up Okasaki as well.
It still needs some more documentation, but it definitely is stable enough to release on Hex.PM as-is.

Qqwy

Qqwy OP

TypeCheck Core Team

And a final one for today: Arrays.

Similar to Prioqueue, Okasaki and Sets, this is a common interface to work with arrays that have fast random element access.

It contains two implementations right now, namely a version that wraps Erlang’s :array, and MapArray that uses integer keys as indexing into a map (But in a somewhat different way than I do it in Tensor; MapArray is not a sparse but a terse representation).

Qqwy

Qqwy OP

TypeCheck Core Team

And… Sets is released!

Similar to Prioqueue and Okasaki, this is a common interface to work with Sets, with multiple implementations that can be chosen between either when creating the set, or in your application’s documentation.

Implementations for MapSet, :sets, :gb_sets and :ordsets are included.

Qqwy

Qqwy OP

TypeCheck Core Team

Oh, before I forget!

Extractable and Insertable have been updated to 0.2.0 as well. This is a backwards-incompatible change. (But probably the last; I think the API is now stable and if this is indeed the case, soon a stable 1.0 version will be released).

The backwards-incompatible change is that in case of errors, instead of returning :error, the implementations should return {:error, reason}, with standardized reasons for Extractable being :empty, and for Insertable being :invalid_item_type and :full.


Prioqueue has been updated to reflect these changes as well, now being version 0.2.4 :slight_smile: .

Qqwy

Qqwy OP

TypeCheck Core Team

All right!

Tensor has been updated to version 2.0. This version is backwards incompatible because of multiple major changes:

  • All modules are moved under the single Tensor namespace, to follow HexPM package publishing rules. use use Tensor to alias all of Tensor, Matrix and Vector in your code and us them just as before.
  • Numbers has had multiple important changes between version 1.0 and 4.0, these changes have been reflected in Tensor.
    Other, new features are:
  • FunLand.Mappable implementation, FunLand.Reducable implementation.
  • Extractable implementation.
  • Insertable implementation.
  • Tests for the above.

Where Next? Top

Trending in Discussions Top

cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
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
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
achempion
I’ve been using Emacs as my main code editor for more than a two years. It’s a custom build version although I’ve tried doom emacs and sp...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews