First the function **char64** generates the Base64 character set. Then the routine **base64** takes a string and a stream, and outputs the Base64-encoded version of the string to the stream:

(defun char64 (n) (char "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" (logand n #x3F)))

(defun base64 (str stm) (let* ((l (length str)) (max (ceiling l 3))) (setq str (concatenate 'string str (string #\null) (string #\null))) (dotimes (i max) (let* ((w (* i 3)) (a (char-code (char str w))) (b (char-code (char str (1+ w)))) (c (char-code (char str (+ 2 w))))) (princ (char64 (ash a -2)) stm) (princ (char64 (logior (ash a 4) (ash b -4))) stm) (princ (if (>= (1+ w) l) "=" (char64 (logior (ash b 2) (ash c -6)))) stm) (princ (if (>= (+ 2 w) l) "=" (char64 c)) stm))) (princ #\return stm) (princ #\newline stm)))

It's based on the fact that every three ASCII characters are encoded as four Base 64 characters, using "=" characters to pad strings with a length that's not a multiple of three. For example:

> (base64 "Mind your own business" nil) TWluZCB5b3VyIG93biBidXNpbmVzcw== #\Newline

It terminates the stream with return, newline, as required by the mail protocol.

Here's the function **send** which sends an email from the ESP32 ^{[3]}:

(defun send (message) (with-client (s "mail.mysite.com" 25) (println "EHLO mysite.com" s) (println "AUTH LOGIN" s) (base64 "david" s) (base64 "secret" s) (println "MAIL FROM:david@interface.co.uk" s) (println "RCPT TO:david@technoblogy.com" s) (println "DATA" s) (println message s) (println "." s) (println "QUIT" s)))

The username and password are provided on the two lines following the **AUTH LOGIN** command, encoded using Base64 encoding.

For example, you could run this by evaluating:

(send "Hello from Lispology!")

There are other headers you can provide, such as a subject line, but this example shows the minimum. The body of the message follows the DATA command, and is terminated by a line containing just a full stop.

This example assumes that there are no errors, and ignores the responses from the server. A better implementation would read the server response and check the return code at the start of each line.

- ^ Base64 on Wikipedia.
- ^ ESP32 boards on uLisp.
- ^ Wi-Fi examples on uLisp.

(mapcar #'- '(1 2 3 4))

a much neater way of negating every number in a list, than:

(let (result) (dolist (i '(1 2 3 4) (reverse result)) (push (- i) result)))

However, I often wish that if one of the arguments to **mapc** or **mapcar** was an atom, rather than list, that item would be repeated for each evaluation of the function. So if we wanted to double every number in a list I'd like to be able to write:

(mapcar #'* '(1 2 3 4) 2)

but this is invalid in Common Lisp and gives an error such as:

Error: 'mapcar' third argument is not a list

A typical application often occurs with my uLisp interpreter for the Arduino ^{[1]}; this provides a function **pinmode** to define whether a pin is an input or output; so:

(pinmode pin nil)

makes **pin** an input, and:

(pinmode pin t)

makes it an output. What I would like to be able to do is call:

(mapc #'pinmode '(1 2 3 4) t)

to define all the pins 1 to 4 as outputs.

The solution is to write:

(mapc #'(lambda (x) (pinmode x t)) '(1 2 3 4))

which loses some of the elegance of using a mapping function, or:

(mapc #'pinmode '(1 2 3 4) '(t t t t))

which is also a bit ugly.

The great thing about Lisp is that if you don't like something you can usually fix it.

One way to fix it is to write a function **o** that makes a circular list out of its argument:

(defun o (n) (let ((l (list n))) (setf (cdr l) l)))

For example, in LispWorks ^{[2]} evaluating **(o 2)** returns:

> (o 2) (2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 ...)

We can now write things such as:

> (mapcar #'* '(1 2 3 4) (o 2)) (2 4 6 8)

This solves the original problem like this:

(mapc #'pinmode '(1 2 3 4) (o t))

Alternatively we can write a new version of **mapc**, called **mapc***, which automatically repeats an argument if it's an atom rather than a list:

(defun mapc* (fun arg1 arg2) (mapc fun (if (listp arg1) arg1 (o arg1)) (if (listp arg2) arg2 (o arg2))))

Now we can write:

(mapc* #'pinmode '(1 2 3 4) t)

I'll be interested in hearing whether anyone has a more elegant solution to this question

- ^ uLisp - Lisp for microcontrollers.
- ^ Unfortunately my uLisp interpreter doesn't currently know how to print circular lists, so it gets stuck in a loop.

One way would be to define Lisp functions to calculate the resistance of two resistors in series, and of two resistors in parallel:

(defun series (x y) (+ x y)) (defun parallel (x y) (/ (+ (/ x) (/ y))))

Note that in Lisp (/ x) is a shorter way of writing (/ 1 x).

Now we can use these functions to express the complete circuit:

> (parallel (series 5 6) (series (parallel 10 15) 5)) 11/2

and the answer is 11/2 or 5.5 Ω.

This approach seems like it's getting the user to do most of the work. A more intuitive and general way to represent a resistor network would be to label each of the nodes a, b, c, etc and then represent it as a list of the resistances between each pair of nodes. Using this approach the above network becomes:

(defparameter *circuit* '((a d ?) (a b 10) (b a 15) (b d 5) (a c 5) (c d 6)))

The list **(a d ?)** represents the resistance we want to calculate.

It will be useful to have a function **split-set**, that takes a list and an index i, and returns the ith division of the set into two subsets.

(defun split-set (list i) (let (in out (ll (reverse list))) (dotimes (j (length list)) (if (oddp i) (push (nth j ll) in) (push (nth j ll) out)) (setq i (ash i -1))) (values in out)))

For a list of length n the total possible number of subsets is 2^{n}. The function **split-set** works by expressing the index i as a binary number, and it then puts each element into one of the two sets according to whether the bit corresponding to that element is a 0 or a 1. So, for example, 13 in binary is **1101** so the 13th split of the list of four elements (a b c d) is:

CL-USER > (split-set '(a b c d) 13) (A B D) (C)

To simplify the network we successively combine pairs of resistors according to the rules of parallel and series resistors. To do this we look at every possible pair of resistors and see if they can be combined into a single resistor. For example, the two parallel resistors between a and b could be merged into a single resistor.

Here's the routine **series-parallel** to combine two resistors x and y. It also takes the entire circuit as a parameter so we can check for other connections between the same nodes:

(defun series-parallel (l x y) (cond ((or (eq (caddr x) '?) (eq (caddr y) '?)) nil) ;; Check four possible labellings ((dolist (x (list x (list (second x) (first x) (third x)))) (dolist (y (list y (list (second y) (first y) (third y)))) ;; Resistors in parallel (when (and (eq (first x) (first y)) (eq (second x) (second y))) (return-from series-parallel (list (list (first x) (second x) (/ (+ (/ (third x)) (/ (third y)))))))) ;; Resistors in series (when (and (eq (first x) (first y)) (= (countlinks l (first x)) 2) (not (eq (second x) (second y)))) (return-from series-parallel (list (list (second x) (second y) (+ (third x) (third y))))))))) (t nil)))

For two resistors in parallel we simply need to check that their start and end nodes are the same. For example, here it combines the resistors between a and b:

CL-USER > (series-parallel *circuit* '(a b 10) '(b a 15)) ((A B 6))

For two resistors in series we also need to check that no other resistor is connected to the node between the two resistors; this is what **countlinks** does:

(defun countlinks (l x) (count-if #'(lambda (i) (or (eq x (first i)) (eq x (second i)))) l))

For example, here we combine the two resistors between a, c, and d:

CL-USER > (series-parallel *circuit* '(a c 5) '(c d 6)) ((A D 11))

If it's not possible to combine the resistors **series-parallel** returns nil:

CL-USER > (series-parallel *circuit* '(a b 10) '(b d 5)) NIL

To simplify a circuit we use **split-set** to check every possible pair of resistors to see if they can be combined by **series-parallel**:

(defun simplify (list function n) (let* ((l (length list)) (k (expt 2 l))) (dotimes (i k list) (multiple-value-bind (in out) (split-set list i) (when (= (length in) n) (let ((c (apply function list in))) (when c (return (append c out)))))))))

This function **simplify** takes a list representing the network, a function for combining resistors, and a number of resistors to combine, and returns the simplified network.

Finally to solve the network we call **simplify** repeatedly until there's no more work to do:

(defun solve (circuit) (let (len) (loop (setq len (length circuit)) (setq circuit (simplify circuit #'series-parallel 2)) (when (= (length circuit) len) (return))) circuit))

Here it is working on the above network:

CL-USER > (solve *circuit*) ((A D 11/2) (A D ?))

So the network reduces to a single resistor of 5.5Ω.

I thought I'd solved the problem, but then discovered that there are some networks that this approach can't solve. For example:

This can be represented as the list:

(defparameter *c2* '((a d ?) (a b 32) (b c 24) (a c 25) (b d 32) (c d 40)))

Trying to solve it gives:

CL-USER > (solve *c2*) ((A D ?) (A B 32) (B C 24) (A C 25) (B D 32) (C D 40))

It fails because the circuit doesn't contain any series or parallel configurations that can be simplified.

The solution is to do what's called a Delta-Wye transformation, which converts a triangle configuration, or delta, into a Y or wye configuration by adding an extra node ^{[1]}:

To solve these configurations the function **delta-wye** checks three links, and if they qualify as a delta network, they are transformed into a wye:

(defun delta-wye (l x y z) (declare (ignore l)) (cond ((or (eq (caddr x) '?) (eq (caddr y) '?) (eq (caddr z) '?)) nil) ;; Check eight possible labellings ((dolist (x (list x (list (second x) (first x) (third x)))) (dolist (y (list y (list (second y) (first y) (third y)))) (dolist (z (list z (list (second z) (first z) (third z)))) (when (and (eq (first x) (second z)) (eq (first y) (second x)) (eq (first z) (second y))) (let ((sum (+ (third x) (third y) (third z))) (newsymbol (gensym))) (return-from delta-wye (list (list (first x) newsymbol (/ (* (third x) (third z)) sum)) (list (first y) newsymbol (/ (* (third x) (third y)) sum)) (list (first z) newsymbol (/ (* (third y) (third z)) sum)))))))))) (t nil)))

The function **delta-wye** uses a gensym for the fourth node.

Testing it with x=1, y=2, and z=3 gives:

CL-USER > (delta-wye nil '(a b 3) '(b c 1) '(c a 2)) ((A #:G847 1) (B #:G847 1/2) (C #:G847 1/3))

The **solve** function can be updated to incorporate **delta-wye** as follows:

(defun solve (circuit) (let (len) (loop (setq len (length circuit)) (setq circuit (simplify circuit #'delta-wye 3)) (setq circuit (simplify circuit #'series-parallel 2)) (setq circuit (floating circuit)) (when (= (length circuit) len) (return))) circuit))

I've also added a function **floating** to remove resistors with only one end connected to the network, which can arise from delta-wye transformations:

(defun floating (l) (remove-if #'(lambda (x) (or (= (countlinks l (first x)) 1) (= (countlinks l (second x)) 1))) l))

Testing the new version of **solve** on the network ***c2***:

CL-USER > (solve *c2*) ((D A 32) (A D ?))

and the resistance between a and d is 32Ω.

Finally, try this network containing two deltas:

Here's a complete copy of the Lisp program to solve resistor networks: Resistor network program

- ^ Delta-Wye resistor networks on Khan Academy.