On Sat, Feb 8, 2025 at 10:16 AM Alexander Burger
wrote:
> PicoLisp now has a kind of tail call optimization!
>
I gave 'tco' a try. I appreciate the syntax. The similarity with existing
recur syntax
makes it trivial to convert code where tail calls are possible.
In my bench tests below with a bst search, tail call is on par with
iterative and consistently slightly faster then recur.
Very cool!
/Lindsay
(P.S. In hindsight, BST search trees not being deeply recursive, the
benefit of less resource usage with 'tco' doesn't really apply here)
#
-
# Bench search in a binary search tree (** 2 23) nodes
# using recursive, iterative and tail call search functions. (see code for
functions used at end)
# 1. BST Search for 1M random values in given range that we know are in
tree (so 1M matches)
# Recursive
: (benchFun bstSearch (** 2 23))
100
5.249 sec
# Tail call
: (benchFun bstSearchTco (** 2 23))
100
4.998 sec
# Iterative
: (benchFun bstSearchIter (** 2 23))
100
4.872 sec
# 2. BST Search for 1M random values in given range, most of which may not
be in the tree
# Recursive
: (benchFun bstSearch (** 2 32))
1951
2.962 sec
# Tail call
: (benchFun bstSearchTco (** 2 32))
2014
2.575 sec
# Iterative
: (benchFun bstSearchIter (** 2 32))
1975
2.475 sec
# The bench function (calls given bst search function 1M times with random
values in given range)
(de benchFun (Fun Range)
(bench
(let (N 0)
(do 100
(let (Rnd (rand 1 Range))
(when (Fun '((X) (- X Rnd)) *Tree)
(inc 'N) ) ) )
(prinl N) ) ) )
# Create a balanced binary tree with 2^23 (8388608) nodes
: (gc 256 256)
256
: (off *List) (bench (setq *List (make (for N (** 2 23) (link N) T #
First a list
0.204 sec
-> T
: (off *Tree) (bench (setq *Tree (bstMake *List))) T # Make BST from list
4.014 sec
-> T
: (println (head 7 (make (bstInOrder link *Tree T # InOrder
traversal, head
(1 2 3 4 5 6 7)
-> T
: (println (tail 7 (make (bstInOrder link *Tree T # InOrder
traversal, tail
(8388602 8388603 8388604 8388605 8388606 8388607 8388608)
-> T
# The BST functions
: (mapc pp '(bstMake bstInOrder bstSearch bstSearchIter bstSearchTco))
# Recursive
(de bstSearch (Fun Tree)
(use (Cmp)
(recur (Fun Tree)
(cond
((or
(not Tree)
(=0 (setq Cmp (Fun (car Tree )
Tree )
((lt0 Cmp) (recurse Fun (caddr Tree)))
(T (recurse Fun (cadr Tree))) ) ) ) )
# Tail Call
(de bstSearchTco (Fun Tree)
(use (Cmp)
(tco
(Fun Tree)
(cond
((or
(not Tree)
(=0 (setq Cmp (Fun (car Tree )
Tree )
((lt0 Cmp) (tc Fun (caddr Tree)))
(T (tc Fun (cadr Tree))) ) ) ) )
# Iterative loop
(de bstSearchIter (Fun Tree)
(let (Fin NIL Cmp NIL)
(while (and Tree (not Fin))
(setq Cmp (Fun (car Tree)))
(cond
((=0 Cmp) (setq Fin T))
((lt0 Cmp) (setq Tree (caddr Tree)))
(T (setq Tree (cadr Tree))) ) )
Tree ) )
# Make a BST from ordered list
(de bstMake (L)
(let
(BST
'((L Len)
(recur (L Len)
(when L
(let
(Mid (/ Len 2)
LeftT (cut Mid 'L)
Root (++ L)
RightT L )
(list
Root
(recurse LeftT Mid)
(recurse RightT (if (gt0 Mid) (dec Mid) Mid)) ) ) )
) ) )
(BST L (length L)) ) )
# In order BST traversal
(de bstInOrder (Fun Tree)
(recur (Fun Tree)
(when Tree
(if (atom Tree) (setq Tree (list Tree)))
(recurse Fun (cadr Tree))
(Fun (car Tree))
(recurse Fun (caddr Tree)) ) ) )