timCF

timCF

Calculus - New data types, private, immutable fields and smart constructors

Hello guys! I implemented another way to create new data types (which are not structs or records) in Elixir. Please check out readme file if you are interested, everything is described in detail with examples:

https://github.com/timCF/calculus

Thanks!

Most Liked

OvermindDL1

OvermindDL1

Oh hey, this looks awesome!

Somebody can say “hey, this is not a constructor function, it’s a syntactic sugar for value, literal Elixir term”. But anyway, this is expression and value of this expression is Elixir struct of URI type. For simplicity I’ll call this thing as default constructor . And this default constructor is always public. Indeed, you can write in any place or your program something like this:

I so agree, it is, by definition, A Constructor of the type.

This is mostly caused by elixir being deficient in its typing system, which comes from it modeling after erlang instead of trying to fix that bug in erlang.

And then Full Lambda Calculus! Church Encoding! Lol. As I’m reading through I’m curious when church encoding of integers will come up, or the various combinators. ^.^

This looks like a data driven DSEL I saw in Elixir, though function wrapping.

iex> s0.(:pop, nil)
** (RuntimeError) For value of the type Stack got unsupported METHOD=:pop with SECURITY_KEY=nil

Heh, cute, I’m guessing you are using a make_ref() for the security key as they are unique references in the beam world? I’ve not looked at the code yet.

Lambda types are inferior in performance to classical data types like records or structs. I

Yep definitely figured that at the start.

  • λ-type constructors and setters ~ 2 times slower then default constructors and setters for structs
  • λ-type getters ~ 6 - 12 times slower then pattern matching on structs (but this is still pretty nice performance)

Not ‘as’ bad as expected though, that’s within the realm of usability considering structs are raw beam code…

You can run benchmarks with mix bench command in terminal

Ooo, my favorite things! ^.^

At the moment we can’t properly use Elixir protocols with values of λ-types (because of the same reason). I have couple ideas about it and maybe will fix it.

I have a couple of ideas for it to work with my ProtocolEx library though, hmm… If only Tuple Calls weren’t removed from the BEAM! That still bugs me to no end… >.>

Internal state of value of λ-type is vulnerable for reading (not writing!) through Function.info/2 core function. At the moment I don’t know how to fix it:

Eh, there are ways to but it would slow down the implementation more so not sure it is worth it…

It’s possible to read internal state using this function, but it’s still impossible to create new corrupted value of λ-type based on this internal state. So all immutable and private data is still really immutable and all values of λ-type are still valid and safe.

Ehhhh, actually you can… ^.^;
I’m leaving work right now or I’d show you how you can break this. :wink:
Ping me tomorrow if you are curious, but in essence you can create almost any internal beam type with :erlang.binary_to_term, including picking it apart with the inverse.

This is a fun looking project though, no church encoding, just lambda encapsulation though, lol. ^.^

lpil

lpil

Creator of Gleam

This is the same cost of a single atom per type as with structs or records, so probably not a problem :slight_smile:

Eiji

Eiji

I really do not recommend this as BEAM have limit of atoms (1_048_576 by default) and this could cause problems in large scaling.

defmacro __using__(_) do
  quote location: :keep do
    import Calculus, only: [defcalculus: 2]
  end
end

I think it’s bad practice to add extra use if only import is called.

Consider using this:

defmacro calculus(opts) do
  quote bind_quoted: [opts: opts], location: :keep do
    {opts[:state], opts[:return]}
  end
end

instead of:

defmacrop calculus(state: state, return: return) do
  quote location: :keep do
    {unquote(state), unquote(return)}
  end
end

defmacrop calculus(return: return, state: state) do
  quote location: :keep do
    {unquote(state), unquote(return)}
 end
end

Generic code could be imported instead.

Here is my proposition how it could look like:

defmodule Example do
  use Calculus, state: user(id: id, name: name, balance: balance)

  defrecordp user([:id, :name, :balance]), default_return: {:literal, :ok}

  # no need to change state
  calculus get_name([name: name], return: name)
  calculus set_name([], arg: new_name, state: new_name)
end

defmodule Example2 do
  use Calculus, state: sample(sum: sum), default_return: :state

  defrecordp sample([:sum])

  calculus add([sum: sum], arg: integer, when: is_integer(integer), state: sum + integer)
  calculus get([sum: sum], return: sum)
  calculus increment([sum: sum], state: sum + 1)
end

In my example use Calculus should do:

  1. Set @before_compile module attribute
  2. Register accumulate module attribute
  3. Import generic functions
  4. Generate security key

calculus macro accepts 2 arguments:

  1. Bindings (inspired by Ecto.Query API)
  2. Options:
    a) arg: passed extra argument (we could optionally add args option here as well)
    b) return: returns binding or literal
    c) state: changes state
    d) when: defines a guard(s)

Finally @before_compile callback would finalize all defined calculuses

Please let me know what do you think about it.

Last Post!

OvermindDL1

OvermindDL1

Lol, nice building on it. ^.^

Where Next?

Popular in Announcing Top

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 54260 488
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44778 311
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
kip
Image is an image processing library for Elixir. It is based upon the fabulous vix library that provides a libvips wrapper for Elixir. I...
622 19610 194
New
trisolaran
Hi! :waving_hand: I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV f...
198 11283 107
New
brainlid
LangChain is short for Language Chain. An LLM, or Large Language Model, is the “Language” part. This library makes it easier for Elixir a...
New
bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
384 14721 119
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44265 214
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement