Number/Parigot.bruijn


# MIT License, Copyright (c) 2024 Marvin Borner
# see "on the representation of data in lambda-calculus" (Parigot 1989)
# has a "one-step" predecessor *and* addition function

# Compared to unary/church, they're also faster in many reducers

:import std/Combinator .
:import std/Logic .

# zero Parigot number
zero i ⧗ Parigot

# returns true if Parigot number is zero
zero? [0 [true] [false]] ⧗ Parigot → Boolean

=?‣ zero?

:test (=?zero) (true)
:test (=?[[0 1]]) (false)
:test (=?[[0 [0 2]]]) (false)

# increments Parigot number
inc q''' ⧗ Parigot → Parigot

++‣ inc

:test (++zero) ([[0 1]])
:test (++[[0 1]]) ([[0 [0 2]]])

# decrements Parigot number
dec r i ⧗ Parigot → Parigot

--‣ dec

:test (--(++zero)) (zero)
:test (--[[0 [0 2]]]) ([[0 1]])

# decrements Parigot number with `dec 0 = 0`
dec' [0 [[[0]]] [[0]] [1 0 [0]]] ⧗ Parigot → Parigot

# adds two Parigot numbers
add b ⧗ Parigot → Parigot → Parigot

…+… add

:test (add (inc (zero)) (inc (inc zero))) (inc (inc (inc zero)))

# multiplies two Parigot numbers
# [[iter zero (add 1) 0]]
mul [[[1 [[[0]]] 0 0] [[[4 (2 1 1 0)]]]]] ⧗ Parigot → Parigot → Parigot

…⋅… mul

:test ((inc zero) ⋅ zero) (zero)
:test ((inc zero) ⋅ (inc (inc zero))) (inc (inc zero))
:test ((inc (inc (inc zero))) ⋅ (inc (inc zero))) (inc (inc (inc (inc (inc (inc zero))))))

# subtracts two Parigot numbers
# will not give correct results when b>a in a-b (use sub' then)
# [[iter 1 dec 0]]
sub [[[1 [[4]] 0 0] [[[2 1 1 0 [0]]]]]] ⧗ Parigot → Parigot → Parigot

…-… sub

:test ((inc zero) - zero) (inc zero)
:test ((inc (inc (inc zero))) - (inc zero)) (inc (inc zero))

# subtracts two Parigot numbers such that a-b=0 if b>a
sub' [[[0 [[3]] 2 2]]] [[dec' (1 0 0)]] ⧗ Parigot → Parigot → Parigot

…-*… sub'

:test ((inc zero) -* zero) (inc zero)
:test ((inc (inc (inc zero))) -* (inc zero)) (inc (inc zero))
:test ((inc zero) -* (inc (inc zero))) (zero)

# returns true if Parigot number is greater than other Parigot number
gt? not! ∘∘ (zero? ∘∘ sub') ⧗ Parigot → Parigot → Parigot

iter [[[0 ι ρ ρ]]] ⧗ a → (a → a) → Parigot → a
	ρ [[3 (1 0 0)]]
	ι [[4]]

:test (iter zero inc (inc (inc (inc zero)))) (inc (inc (inc zero)))

rec [[[0 ι ρ ρ --0]]] ⧗ Parigot → (Parigot → Boolean) → Parigot → Parigot
	ρ [[[4 0 (2 1 1)]]]
	ι [[[5]]]