The VikiD Truth

Knowledge base / Computing / Lisp family

PicoLisp By Example

The plain idea

This page is my personal problem set for learning PicoLisp by doing: small, interesting programming problems, each worked through in idiomatic PicoLisp. Every solution below was re-run on PicoLisp 26.9 (pil21) in October 2026.

Why learning by example works

PicoLisp is small and unusually consistent, which makes it ideal for this. Each problem shows a pattern (recursion, make/link, filter, fish, tco) that you will meet again and again in real code.

An everyday analogy

You do not learn a language from a phrasebook; you learn it by having real little conversations. These problems are those conversations: short enough to finish, real enough to teach.

A note on the sources

PicoLisp by Example (by Alexander Burger and Thorsten Jolitz) is a book. Its first part solves the 99 Lisp Problems, which began as a Prolog problem list by Werner Hett (P-99). Its second part collects 600+ Rosetta Code tasks. Rosetta Code is still the biggest public collection of PicoLisp solutions. The book was written in the pil32/pil64 era, so a few examples need small changes on pil21: library namespaces, and demos that were dropped from misc/.

I am not trying to copy that fine piece of work. I use it as inspiration and a guide for my own list of problems and solutions.

The problems

Start the REPL with pil + and type along.

1. Last element of a list (P-99 #1). The recursive version first, then the built-in:

(de myLast (L)
   (if (cdr L) (myLast @) (car L)) )   # @ holds the result of (cdr L)
(myLast (1 2 3 4))   # -> 4
(last (1 2 3 4))     # -> 4

2. Reverse a list (#5), by pushing onto an accumulator:

(de myRev (L)
   (let R NIL
      (for X L (push 'R X))
      R ) )
(myRev (1 2 3))   # -> (3 2 1)

3. Palindrome (#6). A string becomes a list of characters with chop:

(de pal? (L) (= L (reverse L)))
(pal? (chop "racecar"))   # -> T

4. Flatten a nested list (#7). fish collects every element that satisfies a test:

(fish atom '(a (b (c d) e)))   # -> (a b c d e)

5. Eliminate consecutive duplicates (#8). make/link build a list, and made lets you look at it while it grows:

(de compress (L)
   (make
      (for X L
         (unless (= X (last (made))) (link X)) ) ) )
(compress '(a a a b c c a a d e e e))   # -> (a b c a d e)

6. Pack runs into sublists, then run-length encode (#9, #10):

(de pack2 (L)
   (make
      (while L
         (let X (car L)
            (link (make (while (= X (car L)) (link (pop 'L))))) ) ) ) )
(pack2 '(a a b c c c))   # -> ((a a) (b) (c c c))

(de encode (L)
   (mapcar '((G) (list (length G) (car G))) (pack2 L)) )
(encode '(a a a b c c))  # -> ((3 a) (1 b) (2 c))

7. Primes (#31, #39). A loop with two exit clauses:

(de prime? (N)
   (and (> N 1)
      (let D 2
         (loop
            (T (> (* D D) N) T)
            (T (=0 (% N D)) NIL)
            (inc 'D) ) ) ) )
(filter prime? (range 1 30))   # -> (2 3 5 7 11 13 17 19 23 29)

8. Fibonacci with bignums. swap sets a variable and returns its old value:

(de fib (N)
   (let (A 0 B 1)
      (do N (setq B (+ (swap 'A B) B)))
      A ) )
(fib 100)   # -> 354224848179261915075

9. FizzBuzz (Rosetta Code):

(for I 15
   (prin
      (cond
         ((=0 (% I 15)) "FizzBuzz")
         ((=0 (% I 3)) "Fizz")
         ((=0 (% I 5)) "Buzz")
         (T I) )
      " " ) )

10. Deep recursion without stack growth. This uses tco/tc, which were added in pil21. Plain recursion a million levels deep would exhaust the stack; this runs as a loop:

(de sumTo (N)
   (let Acc 0
      (tco (N Acc)
         (if (=0 N)
            Acc
            (tc (dec N) (+ Acc N)) ) ) ) )
(sumTo 1000000)   # -> 500000500000

11. GCD. There is no built-in gcd, so write Euclid’s algorithm:

(de gcd (A B) (if (=0 B) A (gcd B (% A B))))
(gcd 36 60)   # -> 12

Patterns worth noticing

More

Last edited · 5 revisions

Tags: #Computing