Qqwy

Qqwy

TypeCheck Core Team

Numbers: A generic wrapper to use *any* custom Numeric type!

Hey, everyone!

Today I started writing a small library to perform computations with Complex Numbers. (ComplexNum, it is still very much unfinished). While working on that, I realized that I did not only wanted to be able to specify the real and imaginary parts as Integers or Floats, but also Decimals, Rationals or other numeric data types.

This made me realize that it was possible to create a more general ‘dispatching’ module, as long as each of the numeric data types followed the same API (i.e. the same Behaviour):

And thus Numbers was born.

What does it do?

It allows you to call Numbers.add, Numbers.sub, Numbers.mult, etc. regardless of what data types you are performing arithmetic with. As long as they are the same type (or one of them is a built-in data type such as an integer or float, in which case they will be attempted to automatically be converted to the custom data type), it will Just Work™.

Some Examples:

iex> alias Numbers, as: N

iex> N.add(1, 2)
3

iex> N.mul(3,5)
15

iex> N.mul(1.5, 100)
150.0

Using Decimals: (requires the Decimal package)

iex> d = Decimal.new(2)
iex> N.div(d, 10)
#Decimal<0.2>
iex> small_number = N.div(d, 1234)
#Decimal<0.001620745542949756888168557536>
iex> N.pow(small_number, 100)

Using Rationals: (requires the Ratio package)

iex> use Ratio, operators: false
iex> res = N.add(1 <|> 2, 3 <|> 5)
11 <|> 10
iex> N.mult(res, 10)

How does it work?

Simply put, the Numbers module accepts for most functions two arguments that should be of the same struct type (optionally, one of them could be an integer or float which is automatically converted by Numbers to the struct of the other argument). It will extract the module name of the struct, and call the functions named add, sub, etc. on that module.

So Numeric is a Behaviour, to follow. Numbers dispatches that behaviour, which means that you can build functions and data types that wrap any kind of number, including custom-built ones.

Some libraries that now use Number in practice, meaning that they can contain any kind of number and be able to perform mathematical operations on their contents, are Tensor and ComplexNum.

What data types are supported right now?

Right now, I know of the following data types that follow the behaviour:

  • built-in Integers
  • built-in Floats
  • Ratio for rational numbers.
  • Decimal for decimal numbers. (Does not yet formally implement the Numeric behaviour using @behaviour, I’ll create a Pull Request on its repository adding just that shortly. In the meantime, as it already informally follows the behaviour, it already simply works!).

One of the things I like the most, is that the following structures both dispatch using Numbers internally as well as implement the Numeric Behaviour, meaning that they can be used as composite Numeric types, when the type they contain follow the Numeric Behaviour. (So you can do elementwise addition of multiple Vectors of Decimals, or even a Matrix filled with Vectors of Complex numbers of Floats). The possibilities are endless!

  • ComplexNum for complex numbers. (as long as the data type used for the real/imaginary parts itself follows Numeric.
  • Tensor for Vectors, Matrices and higher-order Tensors.

Tl;Dr: Numbers is a wrapper exposing the generic functionality all kinds of (custom or built-in) numeric datatypes have. So you can use it to make your code number-agnostic!

I look forward to any and all feedback from you!

Thanks,

~Wiebe-Marten/Qqwy

Most Liked

Qqwy

Qqwy

TypeCheck Core Team

Hey guys! I am back from vacation, during which I had some great new ideas.

Numbers has been completely overhauled!

A release candidate for version five (v5.0.0-rc0) is now available on Hex. Please give it a whirl and let me know if you find any rough edges.

This is a major version release because the internal structure is completely changed (and some old exceptions that used to be thrown at certain times no longer exist):

  • Instead of one Numeric behaviours as previously, a whole set of Protocols is now used, so types are no longer required to implement all of the operations if only some of them make sense for a certain numeric type (and when you get into more niche mathematical realms like the realm of elliptic curves for instance, these things do happen very frequently).
  • Using protocols also means that libraries are no longer forced to use the (semi-arbitrarily) function names that Numbers uses for the different operations.
  • Dispatching based on (consolidated!) protocols also means that the library should be a lot more performant. Although I have not done any benchmarks, in the old version of the library there were a lot of extra run-time checks going on that are now unnecessary.
  • A new library called coerce now handles the optional coercion of data types. Previously, coercion was something that was completely handled at runtime. Now, most of it already happens at compile-time, meaning that coercion is probably a lot faster too. coerce also has a lot clearer, more explicit way to define coercions, which I am very happy about as well.
  • No longer ‘ad hoc’ Decimal support. Decimal is now an optional dependency with an explicit version number, and a Decimal-implementation of the protocols is made conditionally using Code.ensure_loaded?, so you’ll only need to add Numbers to e.g. your Phoenix project to get started. Since Numbers will automatically coerce integers and floats to decimals if the other number in an operation is a decimal, this might really increase the readability of your mathematical algorithms. Thanks to @ericmj for telling me about optional dependencies, and also for Decimal itself.

I am very eager for feedback! I feel Numbers is getting quite mature now. :grin:

A full-fledged version will be released as soon as I’m convinced there are no glaring oversights anymore, and I’ll update ComplexNum, Tensor, Rational and FunLand at the same time to support the new version as well.

Qqwy

Qqwy

TypeCheck Core Team

Version 5.2 has been released which performs better operator overloading:

Calling use Number, overload_operators: true no longer breaks operators that are used in guard clauses.
To clarify:

defmodule An.Example do
  use Numbers, overload_operators: true

  def foo(a, b) when a + b < 10 do  # Uses the normal guard-safe '+' operator (e.g. Kernel.+/2)
    42
  end
  def foo(c, d) do 
    c + d # Uses the overloaded '+' operator.
  end
end
Qqwy

Qqwy

TypeCheck Core Team

Note that I have published ComplexNum now as well, as its basic API is now finished and stable. (Although there might be some functionality missing, I don’t know :stuck_out_tongue_winking_eye: )

Where Next?

Popular in Announcing Top

ityonemo
Currently just starting out on a new mini-project - getting zig NIFs to run in elixir. https://github.com/ityonemo/zigler The idea here...
New
pkrawat1
Presenting Aviacommerce, open source e-commerce platform in Elixir Aviacommerce is an open source e-commerce platform in Elixir. We at...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
mikehostetler
I’m excited to announce Jido, a framework providing foundational primitives for building autonomous agent systems in Elixir. While develo...
New
maltoe
Hello! Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New
alisinabh
Hey everyone i’ve developed a library for Jalaali calendar for elixir which supports converting Gregorian dates to Jalaali and vice vers...
New
Crowdhailer
Raxx is an alternative to Plug and is inspired by projects such as Rack(Ruby) and Ring(Clojure). 1.0-rc.1 is now available. To use it re...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
markmark206
simple_feature_flags is a tiny package that lets you turn features on or off based on which environment (e.g. localhost, staging, product...
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

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement