Ranges & Iteration
One number-crunching task in all five BEAM languages: sum the integers 1..10 (the answer is 55). Watch how each language produces the sequence and then folds it - Elixir has a first-class 1..10 range plus list comprehensions, Erlang materialises the list with lists:seq/2, Gleam folds the ints with the typed built-in int.range, LFE calls the same lists:seq in S-expressions, and Luerl drops to Lua's classic three-part numeric for loop with a mutable accumulator.
-module(ranges).
-export([run/0]).
run() ->
%% lists:seq/2 materialises the range as a list: [1,2,...,10]
%% then lists:sum/1 folds it down to a single integer.
lists:sum(lists:seq(1, 10)).
%% run() =:= 55
%%
%% A list comprehension can filter/transform on the way:
%% lists:sum([X || X <- lists:seq(1, 10)]) also yields 55.Erlang has no range type: lists:seq(1, 10) eagerly builds the list [1..10], and lists:sum/1 is the ready-made fold for addition. List comprehensions ([X || X <- ...]) sit on top of the same generated list when you need to transform or filter.
# 1..10 is a real Range value (lazy, O(1) to create)
sum = 1..10 |> Enum.sum()
# => 55
# A comprehension fits when you transform/filter first;
# Enum.sum folds the resulting list:
squares_sum = for n <- 1..10, do: n * n
# squares_sum is [1, 4, 9, ...]; Enum.sum(squares_sum) == 385
# Or fold explicitly with the captured + operator:
folded = Enum.reduce(1..10, 0, &+/2)
# folded == 55Elixir's 1..10 is a genuine Range struct that you pipe straight into Enum.sum/1; comprehensions (for n <- 1..10) and Enum.reduce(1..10, 0, &+/2) are the idiomatic ways to map/filter or fold over the same range without ever building an intermediate list by hand.
import gleam/int
import gleam/io
pub fn main() {
// int.range folds straight over the ints: `from` is inclusive and `to`
// is exclusive, so 1..11 visits 1, 2, ..., 10.
let total =
int.range(from: 1, to: 11, with: 0, run: fn(acc, n) { acc + n })
// total == 55
// int.sum is the typed convenience fold for addition over a List(Int):
let also_total = int.sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
// also_total == 55
io.println(int.to_string(total))
io.println(int.to_string(also_total))
// both print "55"
}Gleam's int.range is a built-in fold over the ints from from (inclusive) to to (exclusive), so to: 11 reaches 10; you pass the seed with with: and the reducer fn(acc, n) with run:. int.sum is the typed convenience fold for addition over a List(Int), and int.to_string is required because the compiler never coerces an Int to a String. (list.range, which used to build a List(Int), was deprecated in stdlib v0.69 and removed in v0.71.)
(defmodule ranges
(export (run 0)))
(defun run ()
;; LFE is Erlang in S-expressions, so it calls the same library:
;; (lists:seq 1 10) builds (1 2 ... 10), (lists:sum ...) folds it.
(lists:sum (lists:seq 1 10)))
;; (ranges:run) => 55
;;
;; LFE comprehensions exist too:
;; (lc ((<- x (lists:seq 1 10))) x) rebuilds the list before summing.LFE reaches for the very same lists:seq/lists:sum as Erlang, just written with prefix S-expressions; the lc list-comprehension macro ((lc ((<- x ...)) body)) is available when you need to transform or filter the generated sequence.
-- Lua has no range type; the idiom is the numeric for loop:
-- `for i = start, stop[, step]` counts inclusively from start to stop.
local sum = 0
for i = 1, 10 do -- i takes 1, 2, ..., 10
sum = sum + i -- mutable accumulator
end
print(sum) --> 55
-- A step of 2 would visit 1, 3, 5, 7, 9:
-- for i = 1, 10, 2 do ... endStandard Lua (what Luerl runs) iterates with the three-part numeric for i = start, stop, step loop, whose bounds are inclusive; you accumulate into a mutable local rather than folding, which is the natural Lua style since it ships no higher-order range library.