rosetta/variadic_fixed-point_combinator.bruijn

Problem description

:import std/Combinator .
:import std/Number .
:import std/List .

# ---------------
# explicit Church
# ---------------

# passes all functions explicitly
explicit-y* [[[0 1] <$> 0] ([[1 <! ([[1 2 0]] <$> 0)]] <$> 0)]

# even x = if x == 0 then true else odd? (x-1)
g [[[=?0 [[1]] (1 --0)]]]

# odd x = if x == 0 then false else even? (x-1)
h [[[=?0 [[0]] (2 --0)]]]

# merged even/odd
rec explicit-y* (g : {}h)

:test (^rec (+5)) ([[0]])
:test (_rec (+5)) ([[1]])

# n % 3
mod3 ^(explicit-y* (zero : (one : {}two)))
	zero [[[[=?0 (+0) (2 --0)]]]]
	one [[[[=?0 (+1) (1 --0)]]]]
	two [[[[=?0 (+2) (3 --0)]]]]

:test ((mod3 (+5)) =? (+2)) ([[1]])

# ----------------
# explicit tupling
# ----------------

# passes all functions explicitly
# requires a tuple mapping function first
# or, minified: [[0 0] [[2 (1 1 0) 0]]] (38 bit!)
tupled-y* [y [[2 (1 0) 0]]]

# merged even odd
rec tupled-y* map [0 g h]
	map [&[[[0 (3 2) (3 1)]]]]

# [[1]] / [[0]] are tuple selectors:

:test (rec [[1]] (+5)) ([[0]])
:test (rec [[0]] (+5)) ([[1]])

# n % 3, [[[2]]] selects first tuple element
mod3 tupled-y* map [0 zero one two] [[[2]]]
	map [&[[[[0 (4 3) (4 2) (4 1)]]]]]
	zero [[[[=?0 (+0) (2 --0)]]]]
	one [[[[=?0 (+1) (1 --0)]]]]
	two [[[[=?0 (+2) (3 --0)]]]]

:test ((mod3 (+5)) =? (+2)) ([[1]])

# NOTE: You can merge the mapping argument directly into the list
#       like [[0 (1 A) (1 B) (1 C) ...]]. Then y*=y.

# ---------------
# implicit Church
# ---------------

# passes all functions in a single list
implicit-y* y [[&(1 0) <$> 0]]

# even x = if x == 0 then true else odd? (x-1)
g [[=?0 [[1]] (_1 --0)]]

# odd x = if x == 0 then false else even? (x-1)
h [[=?0 [[0]] (^1 --0)]]

# merged even/odd
rec implicit-y* (g : {}h)

:test (^rec (+5)) ([[0]])
:test (_rec (+5)) ([[1]])

# n % 3
mod3 ^(implicit-y* (zero : (one : {}two)))
	zero [[=?0 (+0) (_1 --0)]]
	one [[=?0 (+1) (^(~1) --0)]]
	two [[=?0 (+2) (^1 --0)]]

:test ((mod3 (+5)) =? (+2)) ([[1]])