# CircuitScheme - Lisp on CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/071/109/medium800/circuitpython_lisp_cycles.png?1550033313 XKCD "Lisp Cycles" CCA Non-Commercial 2.5)

[A previous Adafruit Guide talks about using FORTH and LISP on SAMD51 based boards](https://learn.adafruit.com/alternative-languages-for-programming-SAMD-boards). The performance and memory provide the opportunity to get away from assembly language and C/C++ and use different styles of language. CircuitPython is a perfect example of this. But it does not have to stop there.&nbsp;

A problem is the language implementations ran _on the bare metal_&nbsp;(the hardware), losing many of the advantages that a higher-level language like CircuitPython can provide. Maybe the most important of these is the ability to treat part of the board's flash storage as a USB drive and place source code there simply by editing files directly on the drive or copying them to it (including dragging and dropping).

This guide introduces an implementation of a Lisp dialect very similar to Scheme with an interesting feature: it's written in Python 3. It's called is CircuitScheme. The implementation is based on Lispy.py written some time ago by Peter Norvig who wrote the books&nbsp;[_Artificial Intelligence: A Modern Approach_](http://aima.cs.berkeley.edu/)&nbsp;and&nbsp;[_Paradigms of AI Programming: Case Studies in Common Lisp&nbsp;._](https://github.com/norvig/paip-lisp)&nbsp;He is currently Director of Research at Google. TL;DR he knows his stuff.

Norvig authored two articles that describe the background and implementation of Lispy:

[(How to Write a (Lisp) Interpreter (in Python))](http://norvig.com/lispy.html)

[(An ((Even Better) Lisp) Interpreter (in Python))](http://norvig.com/lispy2.html)

These provide a description of Lispy and a good introduction to the techniques and considerations of implementing another programming language in Python. This guide will not replicate the content of those papers. You may read them, then come back and see how we can use this in CircuitPython.

Python is a a good language for implementing Lisp as it already has a lot of the capabilities that are needed. Being able to leverage Python's garbage collection is especially useful. Lispy goes even further than some implementations in that lists are implemented directly by Python lists.

So we have a Lisp to program in with all the advantages of the CircuitPython infrastructure. It also means that it's easy to add functionality such as support for hardware interaction. We'll cover that later in the guide.

The goal of this guide isn't to teach you Scheme; there are various resources online for that.&nbsp;[https://schemers.org/](https://schemers.org/)&nbsp;is a good central spot to find them. An excellent resource for learning Scheme is [_The Structure and Interpretation of Computer Programs_](https://mitpress.mit.edu/sites/default/files/sicp/index.html) which is a text that was used for first year computer science at MIT for many years. It was co-written by one of the creators of Scheme (and MIT professor), Gerald Sussman. MIT recorded the series of lectures from the course and has made them available, along with electronic versions of the book. In this guide, you will learn Scheme as a side effect of using it as the language used to explore concepts in computing.

## Required Hardware

Lispy will run comfortably on any M4 Express board: Grand Central, Feather, or ItsyBitsy. Do not forget to also get a good USB cable to connect the board to your computer.

Featured
### Adafruit Grand Central M4 Express featuring the SAMD51

[Adafruit Grand Central M4 Express featuring the SAMD51](https://www.adafruit.com/product/4064)
Are you ready? Really ready? Cause here comes the **Adafruit Grand Central** featuring the **Microchip ATSAMD51**. This dev board is so big, it's not named after a Metro train, it's a whole freakin' _station_!

This board is like a freight...

In Stock
[Buy Now](https://www.adafruit.com/product/4064)
[Related Guides to the Product](https://learn.adafruit.com/products/4064/guides)
![Angled Shot of the Adafruit Grand Central M4 Express featuring the SAMD51.](https://cdn-shop.adafruit.com/640x480/4064-05.jpg)

Featured
### Adafruit Feather M4 Express - Featuring ATSAMD51

[Adafruit Feather M4 Express - Featuring ATSAMD51](https://www.adafruit.com/product/3857)
It's what you've been waiting for, the Feather M4 Express featuring ATSAMD51. This Feather is fast like a swift, smart like an owl, strong like a ox-bird (it's half ox, half bird, OK?) This feather is powered by our new favorite chip, the **ATSAMD51J19** -&nbsp; with...

In Stock
[Buy Now](https://www.adafruit.com/product/3857)
[Related Guides to the Product](https://learn.adafruit.com/products/3857/guides)
![Angled shot of a Adafruit Feather M4 Express. ](https://cdn-shop.adafruit.com/640x480/3857-10.jpg)

Featured
### Adafruit ItsyBitsy M4 Express featuring ATSAMD51

[Adafruit ItsyBitsy M4 Express featuring ATSAMD51](https://www.adafruit.com/product/3800)
What's smaller than a Feather but larger than a Trinket? It's an **Adafruit ItsyBitsy M4 Express** featuring the **Microchip ATSAMD51**! Small, powerful, with a ultra fast ATSAMD51 Cortex M4 processor running at 120 MHz - this microcontroller board is perfect...

In Stock
[Buy Now](https://www.adafruit.com/product/3800)
[Related Guides to the Product](https://learn.adafruit.com/products/3800/guides)
![Adafruit ItsyBitsy M4 Express featuring ATSAMD51 connected to a small breadboard. ](https://cdn-shop.adafruit.com/product-videos/640x480/3800-04.jpg)

Featured
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

Out of Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

# CircuitScheme - Lisp on CircuitPython

## Lisp

![](https://cdn-learn.adafruit.com/assets/assets/000/071/110/medium800/circuitpython_lisp.jpg?1550033654 XKCD "Lisp" CCA Non-Commerical 2.5)

So why Lisp? What's so special about it?

## Simplicity

Lisp is one of those languages that is so simple it's almost nonsensically trivial. There is essentially two things to the syntax of Lisp:

1. _Atomic pieces of data_; things that you will be familiar with, like _numbers_, _strings_, and **symbols**. Symbols are similar to identifiers in other languages. They can have a _value bound_ to them. When a symbol is used, it's looked up in the environment and the bound value is used. If it's not found, an error is raised. Like Python identifiers, symbols can have different values, possibly of different types, over time. Additionally in CircuitScheme, atomic data can be any piece of Python data (e.g. an instance of a class).
2. _Lists of data_. Like Python, items in a list can be any data including other lists. Also, like Python, items in a list do not have to be of the same type.

That's it. It gets more interesting when you consider that Lisp code is just Lisp data: there is no difference at all. Data can be evaluated. Atomic data simply evaluates to itself, while symbols get looked up resulting in the bound value.

Evaluating a list is where things get interesting. The first item in the list is expected to evaluate to a function. The rest of the list items are evaluated and used as arguments to that function.

Once more, that's all there is to it.&nbsp; Well, almost. There are a few function-like things that are called _special forms_. They are often implemented in the interpreter, rather than as a function, and take their arguments verbatim, without evaluating them first.

Consider the `if` special form:

`(if condition `  
`  then-expression`  
`  else-expression)`

Based on what the condition evaluates to either the **then** or **else** expression should be evaluated. You can see how they can't be evaluated before being passed to **if** ; we only want to evaluate one of `then-expression` or `else-expression` based on `condition`.&nbsp; There are a handful of forms like this in any Lisp. In Norvig's original version of Lispy, there are 6 of these: `quote`, `if`, `set!`, `define`, `lambda`, and `begin`. The CircuitScheme adds `cond` to the list for convenience.

## Macros

Another defining feature of most Lisp implementations is a very powerful macro system. This makes it possible to build language level capabilities that act like special forms.

For example, having a block of code evaluate when a condition of **true** is very common. With `if` we have to do something like:

`(if condition`  
`  (begin expression-1`  
`         expression-2`  
`         ...))`

This can get unwieldy, and a when macro is often used:

`(when condition`  
`  expression-1`  
`  expression-2`  
`  ...)`

This is a cleaner, more concise alternative. The `when` macro can be written as so:

`(define-macro when (lambda args`  
`  `(if ,(car args) (begin ,@(cdr args)))))`

Even without being familiar with the macro syntax (i.e.: `` , ,@`), it should be clear how `when` is being rewritten into the form using `if` and `begin` as shown above.

## Recursion and Tail Call Optimization

One feature that is required of a proper scheme (but not of other Lisps) is _tail call optimization_. Before diving into this, let's consider recursion.

Writing iterative code should be familiar to everyone whose done any amount of Python programming.

`while True:`  
`    stuff`

Is about as simple of an iteration as you can get. It just does the same thing over and over. That's all iteration is: doing the same thing multiple times. We see this when using _iterables_ in Python. For instance:

`def f(a_list):    for i in a_list:`  
`        print(i)`

We say that we _iterate_ over the list, printing each item.

There isn't a way to do this in CircuitScheme, although _real&nbsp;_Scheme has some iterative control structures. So how do we do this sort of thing in CircuitScheme (and this sort of thing is very common when programming).

Well, the other way to do repeated processing is to use recursion. Instead of doing the same thing for each item, the function calls itself to process the rest of the list. In Python this would be:

`def f(a_list):`  
`    if a_list:`  
`        print(a_list[0])`  
`        f(a_list[1:])`

If `a_list` isn't empty, print the first item and call `f` again with the rest of `a_list` (i.e. from the second item on).

The CircuitScheme equivalent would be:

`(define (f a-list)`  
`  (if (not (null? a-list))`  
`      (begin`  
`        (display (car a-list))`  
`        (newline)`  
`        (f (cdr a-list)))))`

Consider the two examples above as the list gets longer. Specifically think about what a function call does: it allocates some stack space to store enough information so that it can return properly. The call stack is typically allocated some finite amount of memory. Certainly in a microcontroller context that can be fairly small.

The iterative example above uses some stack space when `f` is called and a bit when `print` is called. When `print` returns, that stack space is reclaimed and used again by the next call to `print`. How much stack space we use is independent of the length of the list.

Now consider the recursive example. `f` is called which takes some stack space, as does the call to `print` but it is reclaimed when `print` returns. The embedded call to `f` takes more stack space. That leads to another call to `f` which takes more stack space. In fact, you can see that there is a call to `f` for each item in the list, so the amount of stack space used is proportional to the length of the list. A longer list will result in more stack space being used. Given that the stack has a finite amount of space, this puts a limit on how long of a list can be processed. Too long and we get a stack overflow error.

This would seem to be a bad thing. And it is, but there's a way to mitigate the problem. Tail Call Optimization. What's a _tail call_? That's the name for the style of recursion where the recursive call (when the function calls itself) is the last thing done before the function returns. We can see that that is indeed the case above. The last thing `f` does if the list wasn't empty is call itself with the rest of the list.

The neat thing about tail calls is that they can be changed quite easily into iteration. By doing so, excessive stack use may be avoided. Now the recursive code can process any size of list, just like the iterative one.

Scheme and, more importantly for us, CircuitScheme does this optimization within the evaluator.

Notably the folks that have controlled Python have steadfastly resisted supporting tail call optimization. To be fair, they encourage writing iterative code (just think about iterables, generators, list comprehensions, ...) Python is full of constructs that reinforce an iterative style of thinking. Which is fine, if not a little limiting and not always very mathematically elegant.

## Non-tail Call Recursion

Since we have a special name for tail call recursion it's logical that there are other forms of recursion that are not tail-call. Generating Fibonacci numbers is a great example. Recall that a Fibonacci number is the sum of the two previous ones. I.e. fib(n) = fib(n-1) + fib(n-2). In Lispy, the obvious solution is:

```
(define (fib n)
  (if (<= n 1)
      n
      (+ (fib (- n 1)) (fib (- n 2)))))
```

Note that this does **not** involve tail-calls. Two recursive calls are made and the results added. The last thing done is the addition. Therefore this can not be optimized. We need to restructure it to use a tail-call. In essence we turn it inside out and accumulate the result as we make the recursive calls. When we reach the base-case (n being 0) the result is in hand and is returned, rippling back through the tail-calls. Note that this often requires a helper function (using a nested definition to hide it) in order to maintain the same API:

`(define (fib n)`  
`  (define (iter a b count)`  
`    (if (<= count 0)`  
`        a`  
`        (iter b (+ a b) (- count 1))))`  
`  (iter 0 1 n))`

Now it does use a tail-call and can be optimized by the evaluator. This is a very powerful feature and it's worth making the effort to restructure the recursion to take advantage of it.

# CircuitScheme - Lisp on CircuitPython

## Code

![](https://cdn-learn.adafruit.com/assets/assets/000/071/127/medium800/circuitpython_blinka-small.png?1550109873)

## Getting Familiar

CircuitPython is a programming language based on Python, one of the fastest growing programming languages in the world. It is specifically designed to simplify experimenting and learning to code on low-cost microcontroller boards. Here are some guides which cover the basics:

- [Welcome to CircuitPython!](https://learn.adafruit.com/welcome-to-circuitpython)
- [Adafruit&nbsp;Feather M4 Express](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51) (or whichever board you have chosen)

Be sure you have the latest CircuitPython loaded onto your board per the second guide.

CircuitPython is easiest to use within the Mu Editor. If you haven't previously used Mu,&nbsp;[this guide will get you started](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor).

## Download Library Files

Plug your Feather M4 Express board into your computer via a USB cable. Please be sure the cable is a good power+data cable so the computer can talk to the Feather board.

A new disk should appear in your computer's file explorer/finder called&nbsp; **CIRCUITPY**. This is the place we'll copy the code and code library. If you can only get a drive named&nbsp; **CPLAYBOOT** , load CircuitPython per the guide above.

Create a new directory on the&nbsp; **CIRCUITPY** &nbsp;drive named&nbsp; **lib**.

Download the latest CircuitPython driver package to your computer using the green button below.&nbsp; **Match the library you get to the version of CircuitPython you are using**. Save to your computer's hard drive where you can find it.

[Go to GitHub to get the latest CircuitPython library bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/)
With your file explorer/finder, browse to the bundle and open it up. I advise simply copying all of the libraries to your **CIRCUITPY /lib** directory. You can interact with conceivably any of the libraries with the right wrapper file, so why limit yourself. The M4 boards have plenty of flash to hold it all.

## Getting it

This guide isn't going to do a code walkthrough. Norvig's Lispy pages do that. [You can get the code from GitHub, select Project Zip to get the entire project's files in one Zip file.](https://github.com/adafruit/Adafruit_CircuitScheme)

https://github.com/adafruit/Adafruit_CircuitScheme/blob/master/code.py

# CircuitScheme - Lisp on CircuitPython

## Hardware Extensions

![](https://cdn-learn.adafruit.com/assets/assets/000/071/112/medium800/circuitpython_c64.jpg?1550072913 C64 board  by Christian Taube CCA-SA 2.5)

Hardware support is done with a two level approach.

## Builtin Support

Firstly, the most basic capabilities have been added to the CircuitScheme runtime by way of builtin functions: the board module to give access to pins, digital and analog I/O, I2C bus creation, and sleep.

Let's look at the _Hello, World_ of hardware: blink. It shows setting up a digital output on D13, setting its value, and sleeping. Note it uses recursion. The `let` structure simply binds the symbol `led` to the digital output for use in the code within the `let`.

```auto
(define (blink)
  (let ((led (digital-pin (board "D13") **OUTPUT**)))
    (define (loop val)
      (pin-value! led val)
      (sleep 0.5)
      (loop (not val)))
    (loop #t)))
```

The functions below are supplied. They work as you would expect. Later in the guide, we'll see some examples.

`board-pins` - get a list of the names of all pins on the board  
`board` - given a pin name, return the corresponding pin object  
`digital-pin` - create a DigitalInOut from a pin object  
`analog-pin` - create an analog pin from a pin name and direction  
` **INPUT** ` - use to create a digital or analog input  
` **OUTPUT** ` - use to create a digital or analog output  
` **PULLUP** ` - set a pull up resistor on a digital input  
` **PULLDOWN** `- set a pull down resistor on a digital input  
`pin-value` - get the value (digital or analog) of a pin  
`pin-value!` - set the value (digital or analog) of a pin  
`i2c` - create an I2C bus object given SCL and SDA pins objects  
`sleep` - delay some number of seconds

## Wrapping CircuitPython Driver Libraries

The second approach provides a facility to dynamically load wrappers around Python device driver modules. This will generally just be a Python file, but can involve a file of CircuitScheme code as well. A `.py` and `.scm` file with the same basename can be loaded from the **/devices** subdirectory on `CIRCUITPY`. If either file is not found, it is ignored. The code implementing this is:

def execfile(f):  
&nbsp; &nbsp; exec(open(f).read())

def load\_device(device\_driver\_name):  
&nbsp; &nbsp; try:  
&nbsp; &nbsp; &nbsp; &nbsp; execfile('./devices/{0}.py'.format(device\_driver\_name))  
&nbsp; &nbsp; except OSError:  
&nbsp; &nbsp; &nbsp; &nbsp; pass

&nbsp; &nbsp; try:  
&nbsp; &nbsp; &nbsp; &nbsp; load('./devices/{0}.scm'.format(device\_driver\_name))  
&nbsp; &nbsp; except OSError:  
&nbsp; &nbsp; &nbsp; &nbsp; pass

The load\_device function is bound to **load-device** in CircuitScheme, so to load support for a device (e.g. the Si7021 temperature and humidity sensor) you would use:

`(load-device "si7021")`

Then the functions provided can be used. Here is&nbsp;`devices/si7021.py` (there is no `si7021.scm`):

```auto
import adafruit_si7021

def make_si7021(i2c_bus):
    return adafruit_si7021.SI7021(i2c_bus)

def si7021_relative_humidity(device):
    return device.relative_humidity

def si7021_temperature(device):
    return device.temperature

global_env.storage.update({
    'make-si7021':make_si7021,
    'si7021-relative-humidity':si7021_relative_humidity,
    'si7021-temperature':si7021_temperature
    })
```

This defines three functions that we want to make available: create an Si7021 interface object, read the humidity, and read the temperature. It then makes them available to CircuitScheme code by adding them to the global environment's dictionary: `global_env.storage`

Once loaded, it can be used:

```auto
(load-device "si7021")
(define sensor (make-si7021 (i2c (board "SCL") (board "SDA"))))
(display "Temperature: ")
(display (si7021-temperature sensor))
(newline)
(display "   Humidity: ")
(display (si7021-relative-humidity sensor))
(newline)
```

Which results in:

```CircuitScheme version 1.0: 185280 free bytes`  
`==> (load "si7021-sample")`  
`Temperature: 24.3539`  
`Humidity: 42.3818`  
`==>`

# CircuitScheme - Lisp on CircuitPython

## Examples

The first example is the classic blink code. You can see the creation of a digital output on D13, setting its value and sleeping. Note the use of tail-call recursion to implement the repetition.

```auto
    ;;; Blink the onboard LED

(define (blink)
  (let ((led (digital-pin (board "D13") **OUTPUT**)))
    (define (loop val)
      (pin-value! led val)
      (sleep 0.5)
      (loop (not val)))
    (loop #t)))
  
```

Next we'll add digital input. With a pushbutton between D12 and ground, this code turns the led on when the switch is pushed, off when released.

![](https://cdn-learn.adafruit.com/assets/assets/000/071/113/medium800/circuitpython_digital_input.png?1550074899)

```auto
;;; echo a switch on pin D12 onto the onboard LED

(define (echo)
  (let ((switch (digital-pin (board "D12") **INPUT** **PULLUP**))
        (led (digital-pin (board "D13") **OUTPUT**)))
    (define (loop)
      (pin-value! led (not (pin-value? switch)))
      (loop))
    (loop)))
```

Switching to analog, a potentiometer can be connected to A0 and set it up as an analog input. Then it can be read and the value displayed every half second.

![](https://cdn-learn.adafruit.com/assets/assets/000/071/114/medium800/circuitpython_analog_io.png?1550074918)

```auto
;;; Read an analog input every second and print result

(define (analog)
  (let ((input (analog-pin (board "A0") **INPUT**)))
    (define (loop)
      (display (pin-value input))
      (newline)
      (sleep 0.5)
      (loop))
    (loop)))
```

Flipping it around an LED can be connected to A1. The code below sets it up as an analog output and ramps the value up and down between minimum and maximum values. The LED gets brighter and dimmer. The value is also written to the console.

This code also uses the `cond` special form. It's similar to a `switch` statement in many languages. The `cond` contains a series of _(condition code)_ clauses. The code associated with the first condition that evaluates to **true** is evaluated. FYI,&nbsp; **true** in CircuitScheme is `#t` and **false** is `#f`.

```auto
;;; Ramp an analog output up and down

(define (analog)
  (let ((output (analog-pin (board "A1") **OUTPUT**)))
    (define (loop val delta)
      (let ((new-val (+ val delta)))
        (display new-val)
        (newline)
        (sleep 0.1)
        (cond ((<= new-val 0)
               (loop new-val (* -1 delta)))
              ((>= new-val 65535)
               (loop new-val (* -1 delta)))
              (#t (pin-value! output new-val)
                  (loop new-val delta)))))
    (loop 0 1000)))
```

# CircuitScheme - Lisp on CircuitPython

## Language Reference

CircuitScheme is a language from the Lisp family based on Lispy by Peter Norvig as described in&nbsp;[(How to Write a (Lisp) Interpreter (in Python))](http://norvig.com/lispy.html)&nbsp;and&nbsp;[(An ((Even Better) Lisp) Interpreter (in Python))](http://norvig.com/lispy2.html). As such, it is very similar to Scheme and much of the text here is taken more or less verbatim from the MIT Scheme reference manual.&nbsp;

## Data Types

**Booleans&nbsp;** represent true and false. Boolean literals are `#t` and `#f` for **true** and **false** , respectively. The only thing that is considered to be logically false is `#f`. Everything else is logically **true** , including 0 and the empty list, which may surprise some.

**Numbers** are exactly as they are in Python.

**Strings** are any sequence of characters other than `"` enclosed by a pair of `"`, e.g. `"string"`. If you need to have `"` in a string, use `\"`.

**Symbols** are simple identifiers, e.g. `function-name`. Symbols follow the follow 4 simple rules:

1. can only contain graphic characters (i.e. no control characters)
2. can not contain any of the characters:`();,"`&[]{}\`
3. can not begin with a number or single quote
4. and not contain whitespace

Typically, `-` is used to separate words in a symbol, `_` is used in special symbols (such as system use) to separate words and as a prefix and suffix. The characters `?`, `!`, and `*` are typically used as the final character of a function name to denote:

**?** a predicate, e.g. `null?`

**!** a mutating function (changes the argument rather than returning a modified copy), e.g. `set!`

**\*** a variant of the primary function, e.g. `flatten` (which does a one level flattening of a list) and `flatten*` (which is a recursive `flatten`)

Lists are the central data type in any Lisp. They are simply a non-homogeneous sequence of data items (as above) and/or other lists, surrounded by parentheses: `(1 a #t (1 2 3) "hello")`.

**Functions** are user defined procedures. They are covered in detail later.

**Macros** are user defined syntactic extensions.

Additionally, any piece of CircuitPython data can be used in CircuitScheme, although they can only be created in Python code. See the Hardware Extension section for an example.

## Special Forms
**(lambda _formals_&nbsp;_sexpr..._)**

A **lambda** expression evaluates to a procedure. The environment in effect when the&nbsp; **lambda** expression is evaluated is remembered as part of the procedure; it is called the _closing environment_. When the procedure is later called with some arguments, the closing environment is extended by binding the variables in the formal parameter list to the arguments according in order, left to right. The new environment created by this process is referred to as the _invocation&nbsp;__environment_.

Once the invocation environment has been constructed, the _sexprs_&nbsp;in the body of the&nbsp; **lambda** expression are evaluated sequentially in that environment. This means that the region of the variables bound by the **lambda** &nbsp;expression is all of the _sexprs_&nbsp;in the body. The result of evaluating the last _sexpr_&nbsp;in the body is returned as the result of the procedure call.

_formals_, the formal parameter list, is often referred to as a _lambda list_.

Examples:

`(lambda (x) (+ x x)) ⇒ `

`((lambda (x) (+ x x)) 4) ⇒ 8`

`(define reverse-subtract`  
`  (lambda (x y)`  
`    (- y x)))`  
`(reverse-subtract 7 10) ⇒ 3`

`(define foo`  
`  (let ((x 4))`  
`    (lambda (y) (+ x y))))`  
`(foo 6) ⇒ 10`

**(let ((_variable_&nbsp;_init_)...) _sexpr..._)**

The _inits_&nbsp;are evaluated in the current environment (in some unspecified order), the&nbsp;_variables_&nbsp;are then bound (in an environment extending the one the let is being evaluated in) to fresh locations holding the respective results, the _sexprs_&nbsp;are evaluated sequentially in the extended environment, and the value of the last _sexpr_&nbsp;is returned. Each binding of a _variable_&nbsp;has the sequence of _sexpr_&nbsp;as its region.

Note that the following are equivalent:

`(let ((variable init)...) expression...)`  
`((lambda (variable...) expression...) init...)`

Some examples:

`(let ((x 2)       (y 3))`  
`  (* x y)) ⇒ 6`

`(let ((x 2) (y 3))`  
`  (let ((foo (lambda (z) (+ x y z)))`  
`        (x 7))`  
`    (foo 4))) ⇒ 9`

### **Definitions**

**(define _variable_&nbsp;_sexpr_)**  
**(define _formals_&nbsp;_sexpr..._)**

Definitions may only occur at the top level of a program and at the beginning of a lambda body: that is,  
the body of a `lambda`,`let`, or procedure `define` expression. A definition that occurs at the top level of a program is called a&nbsp;_top-level definition_, and a definition that occurs at the beginning of a body is called an _internal definition_.

The second form is used as a shorthand to define a procedure. We saw earlier how the result of `lambda` can be used as a variable value. The first item in _formals_&nbsp;is not a parameter but the _name_&nbsp;of the resulting procedure; thus&nbsp;_formals_&nbsp;cannot be empty.

Hence the following are identical.

`(define inc (lambda (x) (+ x 1)))`  
`(define (inc x) (+ x 1))`

Using this form of define, a function that accepts a completely option set of arguments can be made:

A top-level definition,

`(define variable sexpr)`

has essentially the same effect as this assignment expression, **if _variable_&nbsp;is bound.** I.e. it binds a new value to the symbol.

`(set! variable expression)`

If _variable_&nbsp;is not bound, however, `define` binds _variable_&nbsp;to a new location in the current environment before performing the assignment (it is an error to perform a`set!` on an unbound variable).

`(define add3``(lambda (x) (+ x 3))) ⇒ unspecified`  
`(add3 3) ⇒ 6`

`(define first car) ⇒ unspecified`  
`(first '(1 2)) ⇒ 1`

An internal definition&nbsp;is a definition that occurs at the beginning of a _body&nbsp;_(that is, the body of a&nbsp; `lambda`, `let`, or procedure `define` expression), rather than at the top level of a program. The  
variable defined by an internal definition is local to the _body_. That is,&nbsp;_variable_&nbsp;is bound rather than assigned, and the region of the binding is the entire&nbsp;_body_. For example,

`(let ((x 5))`  
`  (define foo (lambda (y) (bar x y)))`  
`  (define bar (lambda (a b) (+ (* a b) a)))`  
`  (foo (+ x 3))) ⇒ 45`

### **Assignment**

**(set! _variable_&nbsp;_expression_)**

_expression_&nbsp;is evaluated and the resulting value is stored in the location to which&nbsp;_variable_&nbsp;is bound. The value of the `set!` expression is unspecified.

_variable_&nbsp;must be bound either in some region enclosing the `set!` expression, or at the top level.

`(define x 2) ⇒ unspecified`  
`(+ x 1) ⇒ 3`  
`(set! x 4) ⇒ unspecified`  
`(+ x 1) ⇒ 5`

### **Quoting**

This section describes the expressions that are used to modify or prevent the evaluation of objects.

**(quote _datum_)**

This evaluates to _datum_ which may be any external representation of a CircuitScheme object. Use `quote` to include literal constants in code.

`(quote a) ⇒ a`  
`(quote (+ 1 2)) ⇒ (+ 1 2)`

`(quote datum)`&nbsp;may be abbreviated as `'datum`. The two notations are equivalent in all respects.

`'a ⇒ a`  
`'(+ 1 2) ⇒ (+ 1 2)`  
`'(quote a) ⇒ (quote a)`  
`''a ⇒ (quote a)`

Numeric constants, string constants, character constants, and boolean constants evaluate to themselves, so they don't need to be quoted.

`'"abc" ⇒ "abc"`  
`"abc" ⇒ "abc"`  
`'145932 ⇒ 145932`  
`145932 ⇒ 145932`  
`'#t ⇒ #t`  
`#t ⇒ #t`

**(quasiquote _template_)**

_Backquote_&nbsp;or `quasiquote`&nbsp;expressions are useful for constructing a list&nbsp;structure when most, but not all of the desired structure is known in advance. If no commas appear within the _template_, the result of evaluating is equivalent&nbsp;to the result of evaluating `'template`. If a comma appears within the&nbsp;_template_, however, the expression following the comma is evaluated (i.e.&nbsp;_unquoted_) and its result is inserted into the structure instead of the comma and the expression. If a comma appears followed immediately by an at-sign (@), then the following expression must evaluate to a list; the opening and closing parentheses of the list are then _stripped away_&nbsp;and the elements of the list are inserted in place of the comma at-sign expression sequence. `quasiquote`, `comma`, and `comma-at` are equivalent to ```, `,`, `,@`, respectively.

``(list ,(+ 1 2) 4) ⇒ (list 3 4)`

`(let ((name 'a)) `(list ,name ',name)) ⇒ (list a 'a)`

``(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b) ⇒ (a 3 4 5 6 b)`

``((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))`  
`⇒ ((foo 7) . cons)`

``,(+ 2 3) ⇒ 5`

Quasiquote forms may be nested. Substitutions are made only for unquoted components appearing  
at the same nesting level as the outermost backquote. The nesting level increases by one inside each successive quasiquotation, and decreases by one inside each unquotation.

``(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)`  
`⇒ (a `(b ,(+ 1 2) ,(foo 4 d) e) f)`

`(let ((name1 'x)`  
`      (name2 'y))`  
`  `(a `(b ,,name1 ,',name2 d) e)) ⇒ (a `(b ,x ,'y d) e)`

The above notations and `(quasiquote template)` are identical in all respects and is identical to .

`(quasiquote (list (unquote (+ 1 2)) 4))`  
`⇒ (list 3 4)`

`'(quasiquote (list (unquote (+ 1 2)) 4))`  
`⇒ `(list ,(+ 1 2) 4)`

Unpredictable behavior can result if any of the symbols `quasiquote`, `unquote`, or `unquote-splicing` appear in a _template_&nbsp;in ways otherwise than as described above.

### **Macros**

**(define-macro (_formals_) _template_)**

Create a named macro:

_formals_&nbsp;is the same as in a procedure definition: a name followed by formal parameters,  
if any. **NOTE** &nbsp;that the arguments to a macro invocation are **not** &nbsp;evaluated, but  
are passed as is to the macro to do with as it wishes.

_template_&nbsp;the template expression that is processed when the macro is invoked. The result of evaluating the processed template expression becomes the value of the macro invocation. _template_&nbsp;is typically (even always) a quasiquoted expression using the formal parameter names for purposes of unquotiing in order to fill in the template.

`(define-macro (double x)`  
`  `(+ ,x ,x))`

`(double 5) ⇒ 10`

### **Sequencing**

The `begin` special form is used to evaluate expressions in a particular order.

**(begin _expression..._)**

The _expressions_&nbsp;are evaluated sequentially from left to right, and the value of the last _expression_&nbsp;is returned. This expression type is used to sequence side effects such as input and output. Keep in mind, `begin` does **not** &nbsp;create a nested lexical environment.

`(define x 0)`  
`(begin (set! x 5)`  
`       (+ x 1)) ⇒ 6`

`(begin (display "4 plus 1 equals ")`  
`       (display (+ 4 1)))`  
`⇒ unspecified`

It prints "4 plus 1 equals 5".

Often the explicit use of `begin` is unnecessary, because many special forms already support sequences of expressions (that is, they have an implicit`begin`):

- `cond`
- `define` ;''procedure define'' only
- `lambda`
- `let`  
  

### **Conditionals**

The behavior of the _conditional expressions_&nbsp;is determined by whether objects are true or false. The conditional expressions count only `#f` as false. Everything else, including `#t`, lists, symbols, numbers, strings, and procedures count as true.

In the descriptions that follow, we say that an object has _a true value_&nbsp;or _is true&nbsp;_when the conditional expressions treat it as true, and we say that an object has _a false&nbsp;__value_&nbsp;or _is false_&nbsp;when the conditional expressions treat it as false.

**(cond _clause..._)**

Each _clause_&nbsp;has this form: `(predicate expression...)` where _predicate_&nbsp;is any expression. The last _clause_&nbsp;may be an _else&nbsp;_clause, which has the form: `(#t expression...)`

A `cond` expression does the following:

1. Evaluates the _predicate_&nbsp;expressions of successive _clauses_&nbsp;in order, until one of them&nbsp;evaluates to a true value.
2. When a _predicate_&nbsp;evaluates to a true value, `cond` evaluates the&nbsp;_expressions_&nbsp;in the _clause_&nbsp;in left to right order, and uses the result of the last evaluation&nbsp;as the result of the entire `cond` expression.
3. If all _predicates_&nbsp;evaluate to false values, and there is no _else_&nbsp;clause, the result of the conditional expression is unspecified; if there is an _else&nbsp;_clause, `cond` evaluates its _expressions_&nbsp;(left to right) and returns the value of the last one.  
  
`(cond ((> 3 2) 'greater)`  
`      ((< 3 2) 'less)) ⇒ greater`  
`(cond ((> 3 3) 'greater)`  
`      ((< 3 3) 'less)`  
`      (#t 'equal)) ⇒ equal`

Normally, programs should not depend on the value of a `cond` expression that has no&nbsp;_else_&nbsp;clause. However, some prefer to write `cond` expressions in which at least one of the _predicates_&nbsp;is always true. In this style, the final _clause_&nbsp;is equivalent to an _else_&nbsp;clause.

**(and _expression..._)**

The _expressions_&nbsp;are evaluated from left to right, and the value of the first&nbsp;_expression_ that evaluates to a false value is returned. Any remaining&nbsp;_expressions_&nbsp;are not evaluated. If all the _expressions_&nbsp;evaluate to true values, the value of the last _expression_&nbsp;is returned. If there are no _expressions_&nbsp;then `#t` is returned.

`(and (= 2 2) (> 2 1)) ⇒ #t`  
`(and (= 2 2) (< 2 1)) ⇒ #f`  
`(and 1 2 'c '(f g)) ⇒ (f g)`  
`(and) ⇒ #t`

**(or _expression..._)**

The _expressions_&nbsp;are evaluated from left to right, and the value of the first&nbsp;_expression_&nbsp;that evaluates to a true value is returned. Any remaining _expressions&nbsp;_are not evaluated. If all _expressions_&nbsp;evaluate to false values, `#f`&nbsp;is returned. If there are no _expressions_&nbsp;then `#f` is returned.

`(or (= 2 2) (> 2 1)) ⇒ #t`  
`(or (= 2 2) (< 2 1)) ⇒ #t`  
`(or #f #f #f) ⇒ #f(or) ⇒ #f```

**(if _predicate&nbsp;consequent_&nbsp;[_alternative_])**

_predicate_, _consequent_, and _alternative_&nbsp;are expressions. An `if` expression is evaluated as follows: first, _predicate_&nbsp;is evaluated. If it yields a true value, then _consequent_&nbsp;is evaluated and the result is returned. Otherwise&nbsp;_alternative_ is evaluated and the result is returned. If _predicate_&nbsp;yields a false value and no _alternative_&nbsp;is specified, then the result of the expression is unspecified.

An `if` expression evaluates either _consequent_&nbsp;or _alternative_, never both. Programs should not depend on the value of an `if` expression that has no&nbsp;_alternative_.

`(if (> 3 2) 'yes 'no) ⇒ yes`  
`(if (> 2 3) 'yes 'no) ⇒ no`  
`(if (> 3 2)`  
`    (- 3 2)`  
`    (+ 3 2)) ⇒ 1`

**(when _predicate_&nbsp;_expression..._)**

`when` is a macro based on `if`.

If _predicate_ evaluates to a true value, the sequence of _expressions_&nbsp;is evaluated and the result of the last one is the result of the `when` form, otherwise the result is undefined.

`(when (> x 5)`  
`  (write-line "greater")`  
`  (+ x 2))`

The above is equivalent to the following, but is simpler and clearer.

`(if (> x 5)`  
`  (begin (write-line "greater")`  
`         (+ x 2)))`

**(unless _predicate_&nbsp;_expression..._)**

`unless`&nbsp;is also a macro based on `if`.

If _predicate_ evaluates to logically false, the sequence of _expressions&nbsp;_is evaluated and the result of the last one is the result of the `unless` form, otherwise the result is undefined.

`(unless (> x 5)`  
`  (write-line "greater")`  
`  (+ x 2))`

The above is equivalent to the following, but is much simpler and clearer.

`(if (> x 5)`  
`  ()`  
`  (begin (write-line "greater")`  
`         (+ x 2)))`

## Evaluation

**(apply _function_&nbsp;_list_)**

Apply the function that results from evaluating _function_&nbsp;to the argument list resulting  
from evaluating&nbsp;_list_ which, as indicated, must result in a list.

`(apply + '(1 2)) ⇒ 3`

**(eval _expression_)**

Evaluate _expression_&nbsp;in the current environment.

`(eval '(+ 1 2)) ⇒ 3`

## Type tests

**(boolean? _object_)**

Returns whether _object_&nbsp;is a boolean.

**(list? _object_)**

Returns whether _object_&nbsp;is a list.

**(null? _object_)**

Returns whether _object_&nbsp;is an empty list.

**(pair? _object_)**

Returns whether _object_ is a non-empty list. While CircuitScheme does not actually build its lists from pairs (see a scheme/lisp introduction for more on this), instead using Python lists directly, the name for the concept is still used.

**(symbol? _object_)**

Returns whether _object_ is a symbol.

**(port? _object_)**

Returns whether object is a port, i.e. a file-like object.

## Numerical Operations

**(+ _number1 number2_)  
(\* _number1_ _number2_)**  
**(- _number1_ _number2_)**  
**(/ _number1_ _number2_)**

These work as expected.

**(not _object_)**

Results in the logical negation of _object_. Keep in mind that anything other than `#f` is a true value.

`(not #t) ⇒ #f`  
`(not #f) ⇒ #t`  
`(not 0) ⇒ #f`

Operations and constants from CircuitPython's math module are directly available from CircuitScheme. E.g.

`(sin 3.4) ⇒ -0.255541 pi ⇒ 3.14159`

## Numeric Comparisons

These work as expected.

**(= _number1_&nbsp;_number2_)**  
**(\< _number1_ _number2_)**  
**(\> _number1&nbsp;number2)_  
(\<= _number1_ _number2_)**  
**(\>= _number1 number2_)**

## Equality

**(equal? _object1_ _object2_)**

This is equivalent to CircuitPython's `eq` operator.

**(eq? _object1 object2_**)

This is equivalent to CircuitPython's `is` operator.

## List Operations

**(list _object..._)**

Returns a list of its arguments.

`(list 'a (+ 3 4) 'c) ⇒ (a 7 c)`  
`(list) ⇒ ()`

These expressions are equivalent:

`(list OBJ1 OBJ2 ... OBJN)`  
`(cons OBJ1 (cons OBJ2 ... (cons OBJN '()) ...))`

**(cons _obj1 list_)**

Returns a newly allocated pair whose car is _obj1_&nbsp;and whose cdr is&nbsp;_list&nbsp;_(which must be a list).

`(cons 'a '()) ⇒ (a)`  
`(cons '(a) '(b c d)) ⇒ ((a) b c d)`  
`(cons "a" '(b c)) ⇒ ("a" b c)`

**(append _list1 list2_)**

Returns a list consisting of the elements of _list1_&nbsp;followed by the elements of  
_list2_.

`(append '(x) '(y)) ⇒ (x y)`  
`(append '(a) '(b c d)) ⇒ (a b c d)`  
`(append '(a (b)) '((c))) ⇒ (a (b) (c))`

**(car&nbsp;_list_)**

Returns the first item of _list&nbsp;_(i.e. _list_[0] in Python). Note that taking the `car` of the empty list results in an error.

`(car '(a b c)) ⇒ a`  
`(car '((a) b c d)) ⇒ (a)`

**(cdr _list_)**

Returns the contents of the of _list_, other than the first item (i.e. _list_[1:] in Python). Note that taking the `cdr` of the empty list results in the empty list.

`(cdr '(a b c d)) ⇒ (b c d)`  
`(cdr '()) ⇒ ()`

**(length _list_)**

Returns the length of _list_.

`(length '(a b c)) ⇒ 3`  
`(length '(a (b) (c d e))) ⇒ 3`  
`(length '()) ⇒ 0`

## Input/Output

**(open-input-file _filename_)**

Takes a _filename_&nbsp;referring to an existing file and returns an input port capable of delivering characters from the file. Specifying a non-existent file results in an error. This is equivalent to `open(filename)` in CircuitPython.

**(open-output-file _filename)_**

Takes a _filename_&nbsp;referring to an output file to be created and returns an output port capable of writing characters to a new file by that name.&nbsp;This is equivalent to `open(filename, 'w')` in CircuitPython.

**(close-input-port _port_)**  
**(close-output-port _port_)**

Closes _port_&nbsp;and returns an unspecified value. The associated file is also closed.

**(write _object_&nbsp;[_output-port_])**

Writes a representation of _object_&nbsp;to _output-port_ (which defaults to the standard output stream (stdout), and returns an unspecified value. If _object_&nbsp;has a standard external representation, then the written representation generated by `write` shall be parsable by `read` into an equivalent object. Thus strings that appear in the written representation are enclosed in double-quotes, and within those strings backslash and double-quote are escaped by backslashes.` write` performs discretionary output flushing and returns the number of characters written.

**(display&nbsp;_object&nbsp; [output-port]_)**

Works as `write` does except that strings are written without surrounding quotes.

**(newline [out_put-port_])**

Writes an end-of-line to out_put-port_ (defaults to&nbsp;stdout), and returns an unspecified value.

**(read [_input-port_])**

Converts external representations of CircuitScheme objects into the objects themselves. `read` returns the next object parsable from _input-port_ (defaults to the standard input stream (stdin)), updating _input-port_&nbsp;to point to the first character past the end of the written representation of the object. If an end of file is encountered in the input before any characters are found that can begin an object, read returns an end-of-file object. The _input-port_ remains open, and further attempts to read will also return an end-of-file object. If an end of file is encountered after the beginning of an object’s written representation, but the written representation is incomplete and therefore not parsable, an error is signaled.

**(read-char [_input-port_])**

Read a single character from&nbsp;_input-port_ (defaulting to stdin).

**(eof-object? _object_)**

Returns `#t`if _object_&nbsp;is an end-of-file object; otherwise returns`#f`.

**(load&nbsp;_filename_)**

Reads and evaluates code from the file named by _filename_. If&nbsp;_filename_ doesn't end in `.scm` it is appended.

## Call-with-current-continuation (aka&nbsp;`call/cc`)

`call/cc` provides us with a capability comparable to Python's try/except mechanism. This section is cribbed from Norvig's description since it's so good.

Here are some, examples:

`(call/cc (lambda (throw)            (+ 5 (* 10 (call/cc (lambda (escape)                            `&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;`(* 100 (escape 3))))))))⇒ 35(call/cc (lambda (throw)            (+ 5 (* 10 (call/cc (lambda (escape)                                 (* 100 (throw 3))))))))⇒ 3`

In the first example, evaluating&nbsp;`(escape 3)`aborts the current calculation and returns 3 as the value of the enclosing call to&nbsp;`call/cc`. The result is the same as&nbsp;`(+ 5 (* 10 3))`&nbsp;or 35.

In the second example,&nbsp;`(throw 3)`&nbsp;aborts up two levels, throwing the value of 3 back to the top level.

In general,&nbsp;`call/cc`&nbsp;takes a single argument,&nbsp;_proc_, which must be a procedure of one argument.&nbsp;_proc_&nbsp;is called, passing it a manufactured procedure which here is called&nbsp;_throw_. If&nbsp;_throw_&nbsp;is called with a single argument, then that argument is the value of the whole call to&nbsp;call/cc. If&nbsp;_throw_&nbsp;is not called, the value computed by&nbsp;_proc_&nbsp;is returned.&nbsp;

# CircuitScheme - Lisp on CircuitPython

## Next Steps

![](https://cdn-learn.adafruit.com/assets/assets/000/071/111/medium800/circuitpython_steps.jpg?1550068351 "Footprints at the Beach" Hansueli Krapf CC-BY-SA 3.0)

CircuitScheme is quite a nice implementation of a&nbsp;small, but very Scheme-like language. It's a small subset of a full Scheme, but all the crucial parts are present and it's easy to add more. That, in itself, is one of the hallmarks of the Lisp family of languages: it's easy to extend the language in the language itself. This is a big reason for the evolution that Lisp underwent and the diversity of dialects that were created.

So one path forward is to extend the language to be more appropriate for microcontroller work, taking advantage of the CircuitPython substrate.

_Another area of exploration is to improve the REPL. It's very basic at the moment, and more appropriate for its use as a file loader: the `repl` function gets used by `load` to essentially type in code from a file. It needs more editing capabilities_.

UPDATE: CircutiScheme has an expanded REPL interface now. [See this guide for details](https://learn.adafruit.com/a-cli-in-circuitpython). TL;DR it gives you what you'd expect for REPL editing.

A related area is the addition of debugging capabilities.

Finally, more wrappers are needed to support more hardware. As we have seen, it's a fairly simple matter to create a wrapper that imports the CircuitPython device driver and exposes the functions required to let it be used from CircuitScheme.

## In Closing

CircuitScheme is interesting not only because it's a Lisp running comfortably on SAMD51 boards, but because it does so within the CircuitPython environment, leveraging the benefits that provides.


## Guide Products

### Adafruit Grand Central M4 Express featuring the SAMD51

[Adafruit Grand Central M4 Express featuring the SAMD51](https://www.adafruit.com/product/4064)
Are you ready? Really ready? Cause here comes the **Adafruit Grand Central** featuring the **Microchip ATSAMD51**. This dev board is so big, it's not named after a Metro train, it's a whole freakin' _station_!

This board is like a freight...

In Stock
[Buy Now](https://www.adafruit.com/product/4064)
[Related Guides to the Product](https://learn.adafruit.com/products/4064/guides)
### Adafruit Feather M4 Express - Featuring ATSAMD51

[Adafruit Feather M4 Express - Featuring ATSAMD51](https://www.adafruit.com/product/3857)
It's what you've been waiting for, the Feather M4 Express featuring ATSAMD51. This Feather is fast like a swift, smart like an owl, strong like a ox-bird (it's half ox, half bird, OK?) This feather is powered by our new favorite chip, the **ATSAMD51J19** -&nbsp; with...

In Stock
[Buy Now](https://www.adafruit.com/product/3857)
[Related Guides to the Product](https://learn.adafruit.com/products/3857/guides)
### Adafruit ItsyBitsy M4 Express featuring ATSAMD51

[Adafruit ItsyBitsy M4 Express featuring ATSAMD51](https://www.adafruit.com/product/3800)
What's smaller than a Feather but larger than a Trinket? It's an **Adafruit ItsyBitsy M4 Express** featuring the **Microchip ATSAMD51**! Small, powerful, with a ultra fast ATSAMD51 Cortex M4 processor running at 120 MHz - this microcontroller board is perfect...

In Stock
[Buy Now](https://www.adafruit.com/product/3800)
[Related Guides to the Product](https://learn.adafruit.com/products/3800/guides)
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

Out of Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)

## Related Guides

- [Adafruit Feather M4 Express](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51.md)
- [Introducing the Adafruit Grand Central M4 Express](https://learn.adafruit.com/adafruit-grand-central.md)
- [Crickit Powered Mini Chair Swing Ride!](https://learn.adafruit.com/mini-chair-swing-ride.md)
- [Talking Computer from Star Trek](https://learn.adafruit.com/talking-computer-from-star-trek.md)
- [PyPortal MQTT Sensor Node/Control Pad for Home Assistant](https://learn.adafruit.com/pyportal-mqtt-sensor-node-control-pad-home-assistant.md)
- [No-Solder LED Disco Tie with Bluetooth](https://learn.adafruit.com/no-solder-circuit-playground-bluetooth-disco-tie.md)
- [Glowing Lotus Flower - Electronic Origami for Beginners](https://learn.adafruit.com/glowing-lotus-flower-electronic-origami-for-beginners.md)
- [Steven Universe Wearable, Fusable Gem](https://learn.adafruit.com/steven-universe-wearable-fusable-gem.md)
- [Thanksgiving Robotic Turkey Hand with Circuit Playground Express and Crickit](https://learn.adafruit.com/talking-turkey-hand.md)
- [Square NeoPixel Display with Black LED Acrylic](https://learn.adafruit.com/sqaure-neopixel-display-with-black-led-acrylic.md)
- [Magical Cardboard Craft Obsidian Sword](https://learn.adafruit.com/cardboard-obsidian-sword.md)
- [Glowing Interactive Crystal Staff ](https://learn.adafruit.com/glowing-interactive-crystal-staff.md)
- [Mouse and Keyboard Control Using TinyUSB and BLE](https://learn.adafruit.com/mouse-and-keyboard-control-using-tinyusb-and-ble.md)
- [Tiny Museum Tour Device](https://learn.adafruit.com/tiny-museum-tour-device.md)
- [Garmin Lidar Lite Range Finder](https://learn.adafruit.com/garmin-lidar-lite-range-finder.md)
- [PyPortal Event Count-Up Clock](https://learn.adafruit.com/pyportal-event-count-up-clock.md)
- [Cellular Data for CircuitPython with FONA](https://learn.adafruit.com/cellular-data-for-circuitpython-with-fona.md)
