On Sat, Feb 8, 2025 at 10:16 AM Alexander Burger <picolisp@software-lab.de>
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))
1000000
5.249 sec

# Tail call
: (benchFun bstSearchTco (** 2 23))
1000000
4.998 sec

# Iterative
: (benchFun bstSearchIter (** 2 23))
1000000
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 1000000
            (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)) ) ) )

Reply via email to