
CommunityNews
Tail-call optimization in Elm
What is TCO?
Tail-call optimization (TCO) is a very neat trick that the Elm compiler does to make recursive functions a lot more performant and stackoverflow-proof.
Evan Czaplicki describes it very well in this article and I recommend you go read it. He calls it tail-call elimination but it’s a different name for the same thing.
To summarize Evan’s article, a “tail-call optimized” function is a recursive function that gets compiled to using a loop instead of function calls to itself. Let’s take the following code as an example…
Read in full here:
This thread was posted by one of our members via one of our news source trackers.
Most Liked

OvermindDL1
That’s not TCO that Elm does, it’s self-call tail recursive optimization, it only can happen in fully known contexts and is not general enough to be full TCO. Full Tail Call Optimization is where a call is in the tail-most position of a function, that means you can then compile essentially a goto
to it (or in the Rust proposal a become
for example), this means the call can be dynamically made, can be any amount deep through any amount of function stacks, etc… etc… I really don’t like how the Elm community keeps trying to misrepresent things about the Elm language, it’s an annoying recurring pattern…
In fact, let’s try it, I go to: Try Elm!
And I try running:
import Html exposing (text)
entry f i acc = if i <= 0 then acc else f (i - 1) (acc + i)
dispatch1 i acc = entry dispatch2 i acc
dispatch2 i acc = entry dispatch1 i acc
main =
let i = dispatch1 10000 0 in
text (String.fromInt i)
And the result is:
Initialization Error
InternalError: too much recursion
Well, let’s try this in Elixir, a language that DOES support TCO, so the same code ported running through the repl:
❯ iex
Erlang/OTP 24 [RELEASE CANDIDATE 3] [erts-12.0] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit]
Interactive Elixir (1.12.0-rc.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> defmodule TestingTCO do
...(1)> def entry(f, i, acc), do: if(i <= 0, do: acc, else: f.(i-1, acc+i))
...(1)>
...(1)> def dispatch1(i, acc), do: entry(&dispatch2/2, i, acc)
...(1)>
...(1)> def dispatch2(i, acc), do: entry(&dispatch1/2, i, acc)
...(1)> end
{:module, TestingTCO,
<<70, 79, 82, 49, 0, 0, 7, 176, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 202,
0, 0, 0, 20, 17, 69, 108, 105, 120, 105, 114, 46, 84, 101, 115, 116, 105,
110, 103, 84, 67, 79, 8, 95, 95, 105, 110, ...>>, {:dispatch2, 2}}
iex(2)> TestingTCO.dispatch1(10000, 0)
50005000
And since Elixir really does implement TCO and not just a simple recursive loop optimization unlike elm’s communities repeating lies then we can go way way higher!
iex(3)> TestingTCO.dispatch1(1000000, 0)
500000500000
Elm has a lot of issues both as a language and as a community, and passing off a very very common optimization pass performed in almost every language as TCO is just the tip of the iceberg…

AstonJ
Even if it’s not true TCO, performance enhancements are always welcome when it comes to JS land

rustkas
I have already read a lot about the disadvantages of Elm. In your opinion, what is currently better than Elm (in terms of the quality of code generation, what to choose for creating a new application) for the front end part?
Popular Frontend topics










Other popular topics










Latest in Frontend
Latest (all)
Categories:
Popular Portals
- /elixir
- /rust
- /wasm
- /ruby
- /erlang
- /phoenix
- /keyboards
- /js
- /rails
- /python
- /security
- /go
- /swift
- /vim
- /clojure
- /java
- /haskell
- /emacs
- /svelte
- /onivim
- /typescript
- /crystal
- /c-plus-plus
- /tailwind
- /kotlin
- /gleam
- /react
- /flutter
- /elm
- /ocaml
- /vscode
- /opensuse
- /ash
- /centos
- /php
- /deepseek
- /scala
- /zig
- /html
- /debian
- /nixos
- /lisp
- /agda
- /react-native
- /textmate
- /sublime-text
- /kubuntu
- /arch-linux
- /revery
- /ubuntu
- /manjaro
- /spring
- /django
- /diversity
- /nodejs
- /lua
- /slackware
- /julia
- /c
- /neovim