tmbb

tmbb

Plaintext accounting as DSL for finance

Plaintext accounting is a whole philosophy which tries to get the best of both simple paper ledgers (for maximum flexibility and portability) and the capabilities of modern computers (for maximum error-avoidance). Some interesting software in this category is ledger, hledger (similar to ledger, but implemented in haskell) and beancount (similar to the ones above, implemented in python).

I think all the above programs have some important flaws (ledger is actually not very good, hledger seems to be a bit inplexible with imports and beancount makes it very hard to import transaction data whithout looking at the source and writing custom python scripts). I actually like the flexibility of beancount, but I’ve decided to go a little further and implement a ledger as a DSL on top of Elixir.

The idea is very simple: a ledger is a sequence of elixir function calls (which use the process dictionary for shared mutable state, which is safe because everything runs in order) which build a ledger datastructure in the background. This allows us to have an unambiguous grammar with some goodies such as Elixir sigils.

For example, this very simple ledger which features the opening of accounts, a 3-way transaction and a balance check (the numbers are random, nothing actually checks). The functions in this file only generate the ledger, they don’t actually check anything, that is left for an as of yet unimplemented module.

open ~D[1990-04-25], account("Expenses::Groceries"), currency: "EUR", note: "track all groceries"
open ~D[1990-04-24], account("Expenses::Eating out"), currency: "EUR"
open ~D[1990-04-24], account("Expenses::Going out (other)"), currency: "EUR"

open ~D[2010-04-24], account("Assets::Bank::Checking"), currency: "EUR"
open ~D[1990-04-24], account("Assets::Cash"), currency: "EUR"

open ~D[2010-04-24], account("Income::Salary"), currency: "EUR"
open ~D[2010-04-24], account("Income::Studio rent"), currency: "EUR"

txn ~D[2025-07-09], notes: "account", accounts: %{
  account("Income::Studio rent") => ~A[-800 EUR],
  account("Liabilities::Tax::Tax owed on rent") => ~A[224 EUR],
  account("Assets::Bank::Checking") => ~A[576 EUR]
}

balance ~D[2025-07-09], account("Assets::Bank::CGD::Checking"), ~A[200 EUR]

Has anyone here ever tried something like this?

I think this doens’t attempt to sandbox the elixir execution, so a maliciously constructed ledger could do bad things to your computer. However, I believe, it might be easy to sanbox it if one disallows the use of qualified functions.

Showing Posts 1 to 3

waseigo

waseigo

Double-entry book-keeping is something that I’m interested in. I played around with Tigerbeetle many moons ago and found it impressive, but also overkill for my needs.

At some point I’ll build something using this: GitHub - coinjar/ex_double_entry: An Elixir double-entry library inspired by Ruby's DoubleEntry. Brought to you by CoinJar. · GitHub

It might be useful for you too.

sbuttgereit

sbuttgereit

Sorry, but an accounting nit which admittedly is besides the point of your post. The transaction below…

… looks wrong to me. You’re showing that you’re paying a liability, the amount that you owe someone, without ever having booked an expense for which that liability was incurred. Typically, for an incurred tax liability you’d have two transactions.

When the income is earned and on which the taxes are levied:

txn ~D[2025-07-09], notes: "account", accounts: %{
  account("Income::Studio rent") => ~A[-800 EUR],
  account("Expense::Tax::Taxes on rent") => ~A[224 EUR],
  account("Liabilities::Tax::Taxes owed") => ~A[-224 EUR],
  account("Assets::Bank::Checking") => ~A[800 EUR]
}

Later when the taxes are paid:

txn ~D[2025-08-01], notes: "account", accounts: %{
  account("Liabilities::Tax::Taxes owed") => ~A[224 EUR],
  account("Assets::Bank::Checking") => ~A[-224 EUR]
}

This represents that between earning the income which causes the taxes and the actual payment of the taxes, the money was sitting in your checking account. Naturally, if the taxes are paid straight-away, you’d just book the expense and never go to the liability account at all. There’s more to say about this… but this is a forum for Elixir and not accounting… so I’ve already said too much :slight_smile:. Also, I’m not an accountant, but am forced to play one in my daily work with uncomfortable regularity… so I could be completely wrong!

tmbb

tmbb OP

Thank you for the links, but I think the goal of the projects you’ve linked is very different from my own goal. My own goal is to have the elixir script define a ledger (which is of course further processed by code that checks everything is fine). There is no database because the script is the database.

— All posts loaded —

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 92995 915
New
AstonJ
The obligatory hello world thread! Who are you and where are you from? :stuck_out_tongue:
4616 55835 594
New
caslu
I want to open this thread for you all to discuss and help those who really like Ash but are still hesitant to use it in a real project. ...
New
arcanemachine
I was working on an Ecto migration and I needed a timestamp. So, for the nth time, I looked up the different data types for timestamps, a...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
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
matt-savvy
Is there a word for the ~> symbol used in Version strings? Do you also just call it a Squiggle Arrow™ ?!
New

Other Trending Topics Top

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
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews