Qqwy
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:
- No Protocol support.
- No documentation (that is part of IEx).
- No introspection, as they do not work on structs (structs are, after all, an Elixir invention).
- 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?
) - 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?
- Arrays implements some of these:
- Sparse Vectors/Matrices/Tensors: Tensor
- Graphs
- Adjacency list
- Adjacency matrix
- Incidency matrix.
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex










Showing Posts 35 to 26- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
Qqwy
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
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
Okasaki has received an overhaul and is now released as v1.0!
Changes are:
ErlangQueueandErlangDequeimplementations that wrap:queue.FunLand.Mappablefor the queues and deques.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
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.extractwill 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_setsand:gb_treescan be made as well.There are two kinds of Iterators inside Iter:
first/1, next/2-support; they are frequently changed into lists)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
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
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, andMapArraythat uses integer keys as indexing into a map (But in a somewhat different way than I do it in Tensor;MapArrayis not a sparse but a terse representation).Qqwy
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_setsand:ordsetsare included.Qqwy
Oh, before I forget!
ExtractableandInsertablehave been updated to0.2.0as 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 forInsertablebeing:invalid_item_typeand:full.Prioqueuehas been updated to reflect these changes as well, now being version0.2.4Qqwy
All right!
Tensor has been updated to version 2.0. This version is backwards incompatible because of multiple major changes:
Tensornamespace, to follow HexPM package publishing rules. useuse Tensorto alias all of Tensor, Matrix and Vector in your code and us them just as before.Numbershas had multiple important changes between version 1.0 and 4.0, these changes have been reflected in Tensor.Other, new features are:
FunLand.Mappableimplementation,FunLand.Reducableimplementation.Extractableimplementation.Insertableimplementation.