A method that I have not seen yet is an encoding by reference
depth. Specifically, I refer to a nested de Bruijn index that, by
itself, encodes the number:
⟨n⟩d=λS(n)n
For example, the decimal number
4
would be encoded as
⟨4⟩d=λ54.
Isn’t this just so elegant? Because I could not find a name for the
encoding, I call them de Bruijn numerals.
However, during my experiments with this encoding, I made an
unfortunate discovery. While reading up on the theory behind optimal
reduction in some ancient book I found in the library, I stumbled upon
the work “Some Unusual Numeral Systems” by Wadsworth (1980), which was
coincidentally published in the same book as Lévy’s legendary paper on
optimal reduction. In this work, Christopher Wadsworth analyzed
different properties of numeral systems and the requirements they have
to fulfill to be useful for arithmetic.
Specifically, he calls a numeral system adequate if it
allows for a successor (succ) function, predecessor
(pred) function, and a zero? function yielding
a true (false) encoding when a number is zero
(or not). He then went on to show that there can not exist an adequate
numeral system encoding numbers as
⟨n⟩e=λknEn,
with
En
being a normal form and
kn
increasing indefinitely with
n.
And, to be fair, it makes sense: An increasing
n
will require an increasing number of applications scaling with
kn
– thus requiring a zero? function to know the
number already. Otherwise, the increasing abstractions can not be
“collapsed” to terms encoding booleans, as they must have a constant
number of abstractions. (read his paper
for more details)
Unfortunately, a zero? function is required in order to
convert any number from this numeral system to another system. So, even
with these limitations, can the “de Bruijn numerals” still be useful for
anything? What do other arithmetic operations look like?
Arithmetic
The simplest operation is the succ function, which is
minimally defined as
succ=λ321=bk
Proof
To prove:
∀n∈N0:succ⟨n⟩d⇝∗⟨S(n)⟩d
Proof by
β-reduction
(⇝):
succ⟨n⟩d=⇝⇝(λ321)λS(n)nλ2(λS(n)n)1λ2λnS(n)=λS(S(n))S(n)=⟨S(n)⟩d
The pred function can be implemented similarly:
pred=λ2100=w
Proof
To prove:
∀n∈N0:pred⟨S(n)⟩d⇝∗⟨n⟩d
Proof by
β-reduction
(⇝):
pred⟨S(n)⟩d=⇝⇝⇝(λ2100)λS(S(n))S(n)λ(λS(S(n))S(n))00λ(λS(n)S(n))0λλnn=λS(n)n=⟨n⟩d
They both use the fact that the outermost abstraction is always bound
to the inner de Bruijn index. Substituting the index with a reference to
a fresh abstraction results in incrementing/decrementing behavior
(utilizing the shift procedure of
β-reduction
with de Bruijn indices)
One problem of pred is its application to
⟨0⟩d.
Optimally, pred should probably return
λ10
again, but in this case the
ω
combinator
λ100
is returned. I’m not sure if there exists a totalpred function for this encoding.
Now, normally further operations could be defined by recursion ending
with a truthy zero?. Of course, this is not an option for
this encoding.
So instead, here’s an incredibly tiny self-contained addition
function:
add=λ32(10)=b
Proof
To prove:
∀a,b∈N0:add⟨a⟩d⟨b⟩d⇝∗⟨a+b⟩d
Proof by
β-reduction
(⇝):
add⟨a⟩d⟨b⟩d=⇝⇝⇝⇝(λ32(10))(λS(a)a)λS(b)b(λ2(λS(a)a)(10))λS(b)bλ1(λS(a)a)(λS(b)b0)λ1(λS(a)a)(λbb)λ1λaλb[a+b]=λS(a+b)[a+b]=⟨a+b⟩d
Isn’t it magical? This is one of the reasons I still like the
encoding: it abuses the de Bruijn shifting so elegantly! It’s basically
like a metacircular numeral system since it hijacks the host
reducer’s computations!
On the other hand, I was not yet able to come up with further such
elegant functions (maybe you can help?) – instead, I came up with some
hybrid implementations that use multiple different numeral
systems (in this case, Church’s).
Hybrid
A Church numeral is not that different from a de Bruijn numeral, as
it turns out. It is defined like this:
⟨n⟩c=λ10∘⋯∘0n
Converting (“apostatizing”) a Church numeral to a de Bruijn numeral
is done using the conv function:
conv=λ0k=tk
With the internal structure of the Church encoding, this basically
comes down to applying succn−1
times on
k=⟨1⟩d,
as
succ=bk.
Proof
To prove:
∀n∈N0:conv⟨n⟩c⇝∗⟨n⟩d
Proof by beta reduction
(⇝):
conv⟨n⟩c=⇝⇝⇝succ(λ0k)λ0∘⋯∘0n(λ0∘⋯∘0n)kk∘⋯∘kn=bk(bk(…(bk⟨1⟩d)…)λS(n)n=⟨n⟩d
In general, assuming an encoding
e
of
⟨n⟩e
has a zero?* and pred* function, a universal
conversion function conv* can be defined:
conv*=fix(λ3zero?*01(2(succ1)(pred*0)))⟨0⟩d
The function consists of fairly typical fix-recursion
using a left case
(zero?01)
to return the constructed term if the input number is zero and a right
case
(2(succ1)(pred*0))
that calls the fix-induced function recursively with the
incremented de Bruijn numeral and decremented input number.
∗∗∗
Anyway, with the insight on Church numerals, we find that the de
Bruijn numerals are defined from nothing else than
⟨a⟩d=k∘⋯∘ka.
If we now, say, want to multiply a number with a different number
b,
this composition sequence has to be composed
b-times.
mult⟨a⟩d⟨a⟩d⇝∗k∘⋯∘ka∘⋯∘k∘⋯∘kab
And – you might have guessed it – the
n-times
composing Church encoding does exactly that:
⟨a⟩c⟨b⟩d⇝∗⟨a⋅b⟩d
Indeed, any operation on Church numerals can now be made to return a
de Bruijn numeral, simply by applying
⟨1⟩d.
Others can be transformed internally such that they also use de Bruijn
operations:
fac=λ10(λ20(1(λ221(10))))(λ1⟨1⟩d)ifac⟨5⟩c⇝∗⟨120⟩d
Of course – still – the resulting de Bruijn numerals can never be
converted back to an encoding like Church’s.
Next, an actual problem where I use de Bruijn numerals in practice
all the time!
Projections
I always found Church
n-tuples
really hard to work with. This is because selecting the
ith
element – again – requires an increasing number of abstractions! In fact
their behavior is so similar that I could only now make use of them
after gaining insight about de Bruijn numerals. They are defined like
this:
tuplen=λS(n)0n[n−1]…1[x1,x2,…,xn]c=tuplenx1…xn⇝∗λ10x1x2…xn
Retrieving the
ith
element of an
n-tuple
would then look something like this:
selectni[x1,x2,…,xn]c⇝∗xi,
which of course must reject all terms but
xi,
therefore requiring an application of
λS(n)i
to the tuple. Specifically, with Church numerals as parameters,
selector⟨n⟩c⟨i⟩c⇝∗λS(n)i.
Luckily, such a term can be constructed using de Bruijn numerals. The
idea is simple: First, we apply
⟨i⟩d
to
⟨n⟩d,
such that we get
λnλS(i)i.
Then, we remove
i
abstractions such that it yields
λS(n)i.
Using i to pop the abstractions, we get:
selector=λ20(ti)(1k(0k))
(note that
⟨n⟩c(ta)⇝∗λ10aa…an)
Finally, with this knowledge, Church
n-tuples
can be used almost like Church lists. Some further functions:
pushpop0pop1popnmove=λ31(02)=q’’=λ21(λ11)=λ21(λ221)=λ31(2bk0)=λ31(λ13b(λ101)1)
where move moves the first element to the
nth
position, without knowing the size of the tuple!
move⟨i⟩c[x1,…,xn]⇝∗[x2,…,x1,…xn]
Notably, something like move or pop-n
generally requires recursion for Church lists. At the same time for
Church
n-tuples,
something as simple as counting the elements is not possible for the
same reasons as a zero? function for de Bruijn numerals, as
the counting function would have to ignore (and count)
n
applied arguments.
(see also a Forth/postscript-like stack language DSL in bruijn using this stack
encoding here)
Thanks for reading. Please let me know if you know of – or come up
with! – other/better operations for de Bruijn numerals. Contact me via
email. Support on Ko-fi. Subscribe on RSS. Follow on Mastodon.
Wadsworth, Christopher. 1980. “Some Unusual
λ-Calculus
Numeral Systems.” To HB Curry: Essays on Combinatory Logic,
Lambda Calculus; Formalism.
动态网自由门 天安門 天安门 法輪功 李洪志 Free Tibet 六四天安門事件 The
Tiananmen Square protests of 1989 天安門大屠殺 The Tiananmen Square Massacre
反右派鬥爭 The Anti-Rightist Struggle 大躍進政策 The Great Leap Forward
文化大革命 The Great Proletarian Cultural Revolution 人權 Human Rights 民運
Democratization 自由 Freedom 獨立 Independence 多黨制 Multi-party system 台灣
臺灣 Taiwan Formosa 中華民國 Republic of China 西藏 土伯特 唐古特 Tibet
達賴喇嘛 Dalai Lama 法輪功 Falun Dafa 新疆維吾爾自治區 The Xinjiang Uyghur
Autonomous Region 諾貝爾和平獎 Nobel Peace Prize 劉暁波 Liu Xiaobo 民主 言論
思想 反共 反革命 抗議 運動 騷亂 暴亂 騷擾 擾亂 抗暴 平反 維權 示威游行 李洪志
法輪大法 大法弟子 強制斷種 強制堕胎 民族淨化 人體實驗 肅清 胡耀邦 趙紫陽
魏京生 王丹 還政於民 和平演變 激流中國 北京之春 大紀元時報 九評論共産黨 獨裁
專制 壓制 統一 監視 鎮壓 迫害 侵略 掠奪 破壞 拷問 屠殺 活摘器官 誘拐 買賣人口
遊進 走私 毒品 賣淫 春畫 賭博 六合彩 天安門 天安门 法輪功 李洪志 Winnie the
Pooh 劉曉波动态网自由门