# Before You Begin

***Medley Interlisp for the Newcomer*****&#x20;is currently in beta.** Your experience and feedback - as a reader and as a Medley user - will be critical in shaping the v1.0 release of this primer.&#x20;

If you spot anything that could be improved- suggestions, errors, inconsistencies, missing clarifications- the best place to let us know is through GitHub Issues.&#x20;

We've set up [a dedicated issue template for this primer](https://github.com/Interlisp/medley/issues/new?template=primer.yml) to make the process easier.

We look forward to your feedback!


# Introduction

Welcome to Medley Interlisp for Beginners! This primer is intended for readers who've programmed before in at least one other language. We don't assume expertise, but we do expect you to be comfortable with thinking in code and computation. So, some background, even if trivial, always helps!

Interlisp is a dialect of Lisp from the 80s. While Common Lisp was an amalgamation of community-guided standard practices, other interesting dialects at the periphery of the language were set aside. Interlisp is one such dialect of Lisp. Medley is a graphical development environment built to facilitate exploratory and interactive programming with Interlisp and Common Lisp.&#x20;

Combined, Medley Interlisp is a powerful tool for building quick interfaces and modular Lisp programs, with numerous quality-of-life features that still hold value for programmers coming from modern systems.

Before you dive into the primer, do take your time to explore the excellent collection of resources available at <https://interlisp.org/>. As a newcomer, contextualizing this novel system within its history will add more depth and richness to your experience. We urge that you do a bit of self-guided research about Lisp's fascinating history, why it was so significant to the evolution of programming, and how it differs from other languages.&#x20;

If you're looking for a centralized hub of literature related to Interlisp and Medley, look no further than our rich bibliography at <https://interlisp.org/history/bibliography/>.

This primer is a great starting point, serving as a beginner's guide to programming in Interlisp! This text has one goal: to teach you different features of Medley Interlisp while simultaneously building a solid foundation and muscle memory of writing Interlisp and interacting with Medley.&#x20;

It'll cover only a little more than the basics of the environment. For a more comprehensive reference, please refer to the [Interlisp Reference Manual](https://interlisp.org/documentation/IRM.pdf) (IRM).

Take a look at our FAQ section on the website before you start: <https://interlisp.org/project/faqs/>


# Medley Online and Medley Local

#### When to choose which?

You can run Medley either online (through a web browser) or locally. Both are fully capable environments, so rest assured, you don't have to compromise on the features available to you. Choose the online version if you want quick and easy access to Medley. You can log in as a guest and start poking around right away. When you're ready to dive deeper and want to keep track of files and retain the state of your environment across sessions, you can create a free account. Use that to log in for your next sessions. Check out [Access Medley Online](https://interlisp.org/software/access-online/) if you have more questions.

If you prefer a more hands-on, web-independent approach, you can run Medley on your computer. Refer to the documentation here: [Install and Run](https://interlisp.org/software/install-and-run/), to learn more about how to get Medley installed on your specific operating system.&#x20;

Both the online and local versions of Medley let you create, save, and edit files and save the current state of your Medley environment. But the process of doing so differs slightly. Medley's `SYSOUT`\
function saves the current state of Medley's virtual memory in a "sysout file." The section titled *Saving Virtual Memory State* in the [Interlisp Reference Manual](https://interlisp.org/documentation/IRM.pdf) can tell you more about SYSOUT's possibilities.

**Accessing Files**

Once inside Medley Online, to your very left, you'll find a sidebar expandable with a left-arrow icon.&#x20;

<img src="/files/Y428cxOwOsYSoaRhRTNX" alt="" data-size="original"> &#x20;

We'll talk about the other options this sidebar provides. For now, let's focus on the first one, a useful virtual file manager. Click, and you should see a warning that the file manager will open in a new window. Go ahead and press Ok. A new tab should appear in your browser with the following window:

<figure><img src="/files/MVBm6eilgk2LdbnwOSa8" alt=""><figcaption></figcaption></figure>

Right above the text "Name", you'll notice that all our important files are stored inside a folder titled "il".&#x20;

If you're running Medley locally, your system files are also inside a folder titled "il" but your saved files will be in a nested subfolder titled "home". So, when you save files in Medley Online, it's saved to the path `il/`

When you save files in Medley running on your computer, your files are saved to the path: `il/home/username/il/`

{% hint style="info" %}
The first "il" is the default name of the folder where Medley is installed, inside the drive you chose during the installation process.

"username" will, of course, be replaced by your username.
{% endhint %}

For example, I created a PDF in TEdit by typing out the file name and not the full path. Medley let me know that it has been saved to:

<figure><img src="/files/XEobkrze7Ww7Wfz7BKMN" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Here, {DSK} refers to the disk containing your Medley installation.
{% endhint %}

I installed Medley on the R drive, in the Installations/Programs folder. So, I can find the file I just saved at:

<figure><img src="/files/R1qrItpt5cncxOo33U30" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The Medley installation shown above is on Windows 11. Your file paths may slightly vary on other operating systems. For a quick check, try saving a file, and Medley will print out where it's being saved to by default. To learn how to save files, take a look at the chapters: Saving Your Work and TEdit, The Text Editor.
{% endhint %}

As we learn to use `LOAD` , `MAKEFILES`, and other helpful functions related to handling files in Medley Interlisp, we don't need to change our file paths while using either version of Medley, but it's good to be aware where they are located so we can use that information later to organize our files better.


# Understanding and Navigating the Interface

After you start Medley, you should see five distinct sections making up the interface on your screen: the prompt window and the executive window on the left, a bar displaying system information at the top, and the Medley Interlisp logo and a Documentation and Optional Features section on the right.&#x20;

<figure><img src="/files/F4gaP5uLFpSaKLa8caVx" alt=""><figcaption></figcaption></figure>

#### The Executive Window

The Executive Window, or Exec on the left, is the primary window where we can write programs and code to run other features of Medley Interlisp. There are two flavors of the executive window: Interlisp and Common Lisp. The type you're using is displayed in the title bar of the executive window.&#x20;

You can create more executive windows in your LISP flavor of choice through the EXEC menu item. Keep on reading to learn more about menus. Yes, you can have multiple executive windows present at the same time.

When you start Medley, the default executive window prints some system information (which you can ignore), followed by the flavor. A blinking caret/indicator shaped like the head of an upward-pointing arrow on Line 3 tells you the system is ready for input. This is where we'll type (for now!).

<figure><img src="/files/AHxc60h9UPagStorb92B" alt=""><figcaption></figcaption></figure>

❕When you have multiple executive windows open, each Exec keeps track of which number of window it is (as in: is this the second, third, or the seven-hundredth exec) and the line number in relation to the other execs present. So, if you're on Line 8 on one window, the new line when you switch to a new window will be Line 9, even if the previous line was something else.

#### Prompt Window:

The prompt window, located at the top-left part of the screen (above the starting Exec), is a dedicated area for displaying system prompts and messages. We can print our own text here as well. The prompt window displays useful information about your current task and will ask you for the next step.

<figure><img src="/files/lOqLPknaaYg2LhQlI7bU" alt=""><figcaption></figcaption></figure>

#### Who-Line:

<figure><img src="/files/YrGJO9ljd91Y6op29rzn" alt=""><figcaption></figcaption></figure>

This bar displays a bunch of important system information we can gloss over for now. If you left-click on Rdtbl, you'll see a menu appear with options for how Medley should read our syntax. Interlisp, the default readtable, is case-sensitive (so FUNCTION-NAME and function-name are not the same functions).&#x20;

Sometimes, Medley's error-checking module will interpret the right case even if you make a mistake or ask you for confirmation. But if you want a smoother typing experience without having to worry about case, you could switch to the XCL Rdtbl, which treats upper and lower case letters as the same.

#### Help and Optional Features:

To your right is a section titled 'Documentation'. It's a list of web links to helpful resources to aid you during your time with Medley Interlisp. BASICS will take you to the Medley Interlisp Project website's Documentation page. Take your time to browse around because chances are the team behind the project has already answered some of the more common questions and curiosities. MANUAL leads to the Interlisp Reference Manual (IRM). Refer to the IRM when you want to know more about certain aspects of Interlisp and when you're ready to move beyond the primer.

<figure><img src="/files/t5ryfOL4MJ1VFcsFczgd" alt=""><figcaption></figcaption></figure>

#### Menus:

You can open different menus depending on context.\
\
The background menu, which provides general commands, can be accessed by holding down the right mouse button on any empty space on the screen:

<figure><img src="/files/nZ8nUGx1yZ7uwJspBOmS" alt=""><figcaption></figcaption></figure>

Window-specific menus, which offer options unique to the type of window you’re using. They can be brought up by holding down the middle mouse button on the title bar (but not all windows have a context-specific menu):

<figure><img src="/files/eB93nvyoF0vPV8dS1cqj" alt=""><figcaption></figcaption></figure>

and the window-management menu, which appears the same for all windows and helps you modify and arrange your windows:

<figure><img src="/files/NKaQ0Xz9uJ1QoaKs0VtA" alt=""><figcaption></figcaption></figure>

Because Medley Interlisp is a 30-year-old system, navigating the interface is slightly different than the modern computers we are used to. But fear not; your mouse and keyboard are all you need!&#x20;

To select a menu item: Press and hold the right mouse button, move the pointer over the item you want, and then release the right button. The highlighted item will be selected.&#x20;

<figure><img src="/files/WzhImSl7mH7fHkL43dPQ" alt=""><figcaption></figcaption></figure>

To expand a menu item: If the item has a gray arrow, sliding the pointer over it will open a submenu; again, release the right button when the item you want is highlighted. You can technically switch which mouse button is held down while navigating, as long as one button stays pressed, but this is rarely necessary.

<figure><img src="/files/RbLWZdtrnNxJT2sF9t66" alt=""><figcaption></figcaption></figure>

We can also create our own menus and repurpose them for different tasks. You'll learn more about this moving forward!

When interacting with windows, a right-click on the window produces the default contextual menu, which has the following options:

<figure><img src="/files/k7Db29NFnsNstr0TmPuO" alt=""><figcaption></figcaption></figure>

| Menu Item | Action                                                                                                                                                                                                            |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Close     | Closes the window, removing it from the screen                                                                                                                                                                    |
| Snap      | Prompts the user for a region on the screen and creates a new window containing a snapshot (bitmap) of the bits currently in that region                                                                          |
| Paint     | Switches to a drawing mode where the cursor acts as a paint brush. The LEFT button adds bits, and the MIDDLE button erases them. The RIGHT button pops up a command menu to change brush options or stop the mode |
| Clear     | Clears the window by erasing all contents within its boundaries and repositions it to the left margin of the first line of text                                                                                   |
| Bury      | Puts the window on the bottom of the occlusion stack, thereby exposing any windows it was previously hiding                                                                                                       |
| Redisplay | Redisplays the window contents                                                                                                                                                                                    |
| Hardcopy  | Prints the contents of the window to the printer or to a file. Used to produce a PDF.                                                                                                                             |
| Move      | Moves the window to a new location specified by pressing and releasing the LEFT mouse button                                                                                                                      |
| Shape     | Allows the user to specify a new region and size for the existing window contents                                                                                                                                 |
| Shrink    | Reduces the window to an icon (a small black rectangle or specialized shape)                                                                                                                                      |
| Expand    | Appears in place of Shrink when the menu is accessed from an icon (shrunken window). It restores the window associated with the icon and removes the icon                                                         |


# Understanding Lisp Syntax

#### **Endless Parentheses**

At the heart of Lisp, short for List Processing, are, you guessed it, LISTS! Specifically, lists that start with a left parenthesis and close with a right parenthesis.&#x20;

`(1 2 3)`

If you are coming from other languages, you might be used to commas as separators for list items. Items in Lisp lists are instead separated by a space.&#x20;

{% hint style="info" %}
This is why when we name things in Lisp, we use separators other than space.

(eg. `function-name` instead of `function name`)
{% endhint %}

A list in Lisp can contain different types of elements, such as strings, numbers, variables, functions, and other lists.

`(1 "Medley" (3 5 "Interlisp"))`

The above example is a list with three elements: the number 1, the string "Medley", and the list (3, 5, "Interlisp").

In Lisp or Interlisp, a list can hold many kinds of things:

* **Strings** are words or text, like `"hello"`.
* **Numbers** (or numeric literals) are just plain numbers, like `42` or `3.14`.
* **Symbols** are names used for variables or functions, like `X` or `PRINT`.
* **Functions** are actions you can run, like `+` or `CAR`.
* **Lists** are groups of items inside parentheses, like `(A 1 "hi")`.

Each type behaves differently in evaluation: symbols get resolved to their values, functions get applied to arguments, lists are treated as code or data depending on context, numbers evaluate to themselves, and strings also evaluate to themselves without triggering any computation.&#x20;

So if you write `(PRINT "hello")`, Lisp sees `PRINT` as a function, `"hello"` as a string (which stays as-is), and the whole list as a command to run.

Lists are a powerful data structure for representing homogeneous and hierarchical data. While other programming languages have several levels of abstraction to "assist" you in building data structures in various ways, it also results in you having to type a lot of syntactic scaffolding to get to what you need.&#x20;

Lisp, however, is fast and straightforward. Everything we do in Lisp is a tree of lists or lists within lists within lists...`(you (get (the idea)))`. It's easy for us to read, understand, and write, and it's easier for the computer to parse what we write into a structure of meaningful interdependent logic.

#### **REPL**

The REPL, short for READ-EVAL-PRINT-LOOP, is a fundamental part of understanding Lisp. Every piece of code you write first goes through the Reader and then the Evaluator. The Reader translates the characters you type into Lisp objects, called symbolic expressions or s-expressions.

On the surface, s-expressions are written with parentheses, such as `(A B C)`, or with dot notation, such as `(A . B)`. Both are just ways of writing lists and pairs so that the Reader can understand them.

Every Lisp list is actually made from pairs. A pair is created by a cons cell, which holds two values: a CAR (the first element) and a CDR (the rest). Lists are a special kind of pair chain where the last CDR is NIL.

For example, the list `(A B C)` is just shorthand for the dotted form `(A . (B . (C . NIL)))`. In other words, the parentheses version is a more convenient way to write a chain of pairs. The dotted form shows the underlying structure explicitly: each cons cell links an element to the rest of the list. We'll discuss them further in the next chapter.&#x20;

The Lisp evaluator processes s-expressions to produce a result. After the reader translates your code into valid s-expressions, the evaluator steps in to interpret them. It determines the correct order of operations, applies functions to arguments, and resolves variable names to their values. The final result is then passed to the printer to be displayed.

The REPL is a mother listener, of sorts. In Lisp, the REPL is always on-ready to read -> evaluate -> print and repeat.

#### **Single Quote ( ' )**

Some s-expressions are self-evaluating, meaning they represent their own value directly. Numbers and strings are great examples; when you type `42` or `"hello"` into the Lisp REPL, the evaluator simply returns that exact value.

However, most other s-expressions are not self-evaluating. The Lisp evaluator tries to interpret them as code, typically a function call. To prevent this from happening and tell Lisp to treat the expression as literal data, you use the special form `quote`.

The single quote symbol (`'`) is a reader macro, a convenience that's processed *before* evaluation. It's a shorthand that the Lisp reader automatically translates into the `quote` special form. For example, `'expr` is simply a more convenient way of writing `(quote expr)`.

The special form `quote` is handled directly by the evaluator. Unlike a regular function that evaluates its arguments, `quote` prevents its single argument from being evaluated, and returns it as is. This is crucial for treating code as data. Let's look at the difference with an example:

* `'(+ 1 2)`: The single quote stops the evaluator from processing `+` as a function. Instead, it treats the expression `(+ 1 2)` as a list of symbols and numbers, returning it as-is. The reader macro `'` expanded this into `(quote (+ 1 2))` for the evaluator.
* `(+ 1 2)`: Without the quote, the evaluator processes `+` as a function and `1` and `2` as its arguments, and returns the result, `3`.

This ability to treat code as data is one of the most powerful and fundamental features of Lisp. It allows you to write programs that can dynamically generate and manipulate other code.

<br>


# Atoms, Functions and Lists

#### Atoms and S-Expressions

The smallest parts of Lisp code are called atoms. An atom can be a number, a symbol, or a name that identifies a function or variable. Some atoms are built into the language, like `+` for addition, while others are defined by the programmer, like variable names or custom function names.

Everything in Lisp, whether an atom or a collection of atoms, is represented as a symbolic expression, or s-expression. Atoms are s-expressions by themselves, while lists are s-expressions that contain other s-expressions, written with parentheses: `(A B C)` is a list containing three s-expressions.

By combining atoms into lists and other s-expressions, we can build more complex logic and programs.

#### Functions

Functions are reusable tasks broken down into steps for computers to understand. A function is made of three key components:

(1) A name so we can call it. Calling a function tells the computer to start the task.&#x20;

In Interlisp, we can define a function with `DEFINEQ` .&#x20;

`(DEFINEQ (function-name (LAMBDA (X Y) (PRINT X) (PRINT Y))))` defines a function called function-name with the arguments `X` and `Y` and the "forms" `(PRINT X)` and `(PRINT Y)`.&#x20;

We call functions by enclosing them in parentheses: `(function-name X Y)`.

{% hint style="info" %}
Make sure you are in an Interlisp Exec. DEFINEQ is specific to Interlisp and won't work for Common Lisp.
{% endhint %}

(2) A set of directions telling the computer how to perform the task.&#x20;

`LAMBDA` tells Interlisp to evaluate the arguments when the function is called before moving on to executing the forms that follow. We can also use `NLAMBDA`, which does not evaluate arguments before executing forms.

To clarify:&#x20;

LAMBDA: `(DEFINEQ (adder (LAMBDA (X  Y) (+ X Y))))`

* When called `(adder 3 (+ 3 4))` outputs `10`because the LAMBDA function evaluated `(+ 3 4)` before assigning that value to `Y` . So, the output is X (3) + Y (7) = 10.

NLAMBDA: `(DEFINEQ (n-adder (NLAMBDA (X Y)(+ X Y))))`

* When called `(n-adder 3 (+ 3 4))` outputs `(+ 3 4) is not a NUMBER` because it expects `Y` to be  a number that `+`can add to `X` (3) but instead encounters an expression which it has been told not to evaluate by NLAMBDA.

(3) Forms that lay out the logic the function should execute. Think of forms as logic encapsulated as lists that uses the arguments passed.

`(DEFINEQ (seven (LAMBDA NIL (+ 3 4))))`  outputs `7`. The expression `(+ 3 4)` is the last form in the function body.

You probably already know what functions are if you're coming from another programming language. Functions help us organize our code and save us the trouble of repeating ourselves. Think of them as an easy way to ask the computer to complete a complex task. Rather than describing the task every time, we describe it once and call it by its name when needed. A good practice is to make function names simple but descriptive.&#x20;

{% hint style="info" %}
Refer to the [Interlisp Reference Manual's](https://interlisp.org/documentation/IRM.pdf) FUNCTION DEFINITION, MANIPULATION AND EVALUATION chapter to learn more about functions!
{% endhint %}

#### Lists

A list in Lisp is an ordered collection of s-expressions enclosed in parentheses. Lists are fundamental to Lisp because the name itself stands for List Processing. A list can contain atoms, such as numbers or symbols, and other s-expressions. Lists allow Lisp to represent sequences of operations, arguments for functions, or structured data. By combining atoms and lists in this way, we can build expressions of any complexity.

One of Lisp's special powers is *homoiconicity-* the ability to represent both code and data using the same structure: lists. Most programming languages let us automate the manipulation of data. In Lisp, we can go further: we can manipulate our logic/code as data. This opens the door to inspecting, transforming, or even generating code programmatically. Pretty cool!

`CONS` is the primary function for constructing pairs in Lisp. Each pair, called a **cons cell**, contains exactly two parts:

* The **CAR**, which holds the first element
* The **CDR**, which holds the second element

These are historical terms that have persisted from the early days of Lisp. To make them easier to read, Common Lisp also defines `FIRST` as an alias for `CAR` and `REST` as an alias for `CDR`.

Every list in Lisp is made from cons cells linked together. A single cons cell can hold atoms or other cons cells in either its CAR or CDR. Lists end when a CDR is `NIL`.

For example:

* `(CONS 1 2)` produces the dotted pair `(1 . 2)`. Here `1` is the CAR and `2` is the CDR.
* `(LIST 1 2 3)` produces `(1 2 3)`, which is shorthand for `(CONS 1 (CONS 2 (CONS 3 NIL)))`. Each cons cell links one element to the rest of the list.

In other words, `LIST` is just a convenient way to build a chain of cons cells.

{% hint style="info" %}
To wrap your head around the relationship between atoms, lists, and functions, consider this: We can build functions by combining atoms into a list. Our function can be given a name. This name, a symbol, can be used as an atom alongside other atoms in a new list.
{% endhint %}


# Variable Bindings and Scope

In Interlisp, `SETQ` creates a persistent or global binding that keeps its value across computations. In contrast, `LET` and `LET*` create temporary, local variables that exist only within the current expression or function. `LET` evaluates and binds all variables in parallel, so none of them can refer to another defined in the same form. `LET*`, however, binds variables one at a time in sequence, allowing each new variable to use the values of those bound earlier, making it useful for stepwise calculations or dependent local values.

<table data-card-size="large" data-view="cards"><thead><tr><th>Form</th><th>Scope</th><th>Example</th><th>Comments by Line Number</th></tr></thead><tbody><tr><td>SETQ</td><td>Global Binding</td><td><ol><li><code>(SETQ TEMP1 (IPLUS 5 5))</code></li><li><code>(SETQ RESULT (ITIMES 2 TEMP1))</code></li><li><code>(SETQ GLOBAL.VALUE TEMP1)</code></li><li><br><br><br><code>RESULT</code></li></ol></td><td>1. Global assignment: <code>TEMP1</code> is now 10.<br>2. Global assignment: <code>RESULT</code> is now 20.<br>3. Global assignment: <code>GLOBAL.VALUE</code> is now 10.<br>4. Returns the current value of <code>RESULT</code> (20).</td></tr><tr><td>LET</td><td>Local, Parallel Binding</td><td><ol><li><code>(LET ((TEMP1 (IPLUS 5 5))</code></li><li><code>(RESULT 20))</code></li><li><code>(SETQ GLOBAL.VALUE TEMP1)</code><br></li><li><br><br><code>(ITIMES RESULT 2))</code></li></ol></td><td><ol><li>Local bindings: <code>TEMP1 = 10</code></li><li><code>RESULT = 20</code> (Evaluated in parallel. Cannot use TEMP1 here.)</li><li>Global value of <code>GLOBAL.VALUE</code> set to 10.</li><li>Returns <code>(ITIMES RESULT 2)</code> = 40.</li></ol></td></tr><tr><td>LET*</td><td>Local, Sequential Binding</td><td><ol><li><code>(LET* ((TEMP1 (IPLUS 5 5))</code></li><li><code>(RESULT (ITIMES 2 TEMP1)))</code></li><li><code>(SETQ GLOBAL.VALUE TEMP1)</code></li><li><br><br><br><code>RESULT)</code></li></ol></td><td><ol><li>Local binding: <code>TEMP1 = 10</code> </li><li><code>RESULT = (ITIMES 2 TEMP1)</code> = 20</li><li>Global value of <code>GLOBAL.VALUE</code> set to 10.</li><li>Returns local <code>RESULT</code> = 20.</li></ol></td></tr></tbody></table>


# Iterators and Conditionals

Medley offers a set of useful functions and operators for conditionals and loops (e.g., COND, IF, AND, OR, FOR, WHILE). It also provides us with a list of functions to compare our data and understand its type.

You can refer to the [IRM](https://interlisp.org/documentation/IRM.pdf)'s Chapter 9, "Lists and Iterative Statements," for an exhaustive list of available options. Here are a select few as examples:

`(FLOATP X)`: Returns x if x is a floating point number. Otherwise returns NIL.

`(NUMBERP X)`: Returns x if x is a number of any type. Otherwise returns NIL.

`(STRINGP X)`: Returns x if x is a string. Otherwise returns NIL.

`(EQP X Y)`: Returns T if x and y are numbers and equal in value. Otherwise returns NIL.

`(EQUAL X Y)`: Returns T if X and Y are numbers with equal value, or strings with the same sequence of characters, or lists where CAR of X and Y and CDR of X and Y are equal. Otherwise returns NIL.

{% hint style="info" %}
Functions ending with “P” are called *predicates.* They test a condition and return a true value (any non-`NIL` object) or `NIL`.
{% endhint %}

#### Conditionals

You may have used `if/else` statements in other programming languages. In Interlisp, `COND` lets you chain together multiple conditional branches concisely. If you're familiar with `switch` statements in C++ or C#, or `match` blocks in Python, `COND` serves a similar purpose- evaluating conditions in order and returning the result of the first one that succeeds.

A verbose conditional block like `(if A then B else if C then D else E)` can be rewritten instead as:

`(COND (A B)(C D)(T E))`

{% hint style="info" %}
T marks the default value. If all previous condition checks return NIL, then the argument following T is evaluated.
{% endhint %}

The arguments after COND are referred to as clauses.&#x20;

(COND CLAUSE<sub>1</sub> CLAUSE<sub>2</sub> CLAUSE<sub>3</sub> ... CLAUSE<sub>N</sub>)

Each clause is evaluated in order and is a list of the form (P<sub>1</sub> C<sub>1</sub> ... C<sub>1N</sub>). Here, P is the condition to be checked. If P<sub>1</sub> returns true, then C<sub>1</sub> to C<sub>1N</sub> are evaluated sequentially. If P1 is not true, then we evaluate P2 and then P3, and so on. If none of the conditions are true, then `COND` returns NIL.

***

**Do it yourself:** Write a small function using COND to identify whether a value is a string or a number and print that answer.

Your function should look similar to this:

<figure><img src="/files/VWZL6HiwYJFndXRgXqU3" alt=""><figcaption></figcaption></figure>

***

#### Loops

Similar to other languages, you can use operators like FOR and WHILE to set up loops.

`(for X from 1 to 5 do (PRINT X))`

Medley has a large collection of iterative statement operators. Check out the IRM's *Conditionals and Iterative Statements* chapter for a full list. Here's a small collection:

`DO`: Evaluates the form/argument for each iteration.

`COLLECT`:  Puts the value of all iterations in a list.

`JOIN`: Returns a list with all values concatenated.

`SUM`: Returns the sum of all values.

`FROM`: Specifies the starting value.

`TO`: Specifies the end value.

`IN`: Steps through each element of a list, returning the first one that matches a given condition.

`WHEN`: Only runs when the condition is met.

***

**Do it yourself:** Write a loop to collect all the numbers from a list of mixed data in a new list.&#x20;

<figure><img src="/files/692pyioXESJJkgxcW1UN" alt=""><figcaption></figcaption></figure>

Can you put a loop inside a COND statement? Give it a try!


# Build Your First Interactive Program

Building quick and easy interfaces is one of Medley Interlisp's most powerful features. You can always refer to the Interlisp Reference Manual for an exhaustive list of its GUI capabilities. It's time to build our first interactive program—a distress call module for a spaceship.&#x20;

In this chapter, we'll learn to do the following things in Medley:

* Build windows.
* Assign variable names to values.
* Build menus and buttons.
* Attach windows and menus.
* Build functions.
* Display function outputs in windows.
* Connect functions to button clicks.

***

Medley has predefined formats to follow when you want to create objects like windows and menus.&#x20;

To create a window, we follow the format: `(CREATEW REGION TITLE BORDERSIZE)`. In the Interlisp Exec, type: `(CREATEW NIL "DISPLAY MODULE" 10)`. You can now click and drag to create a new window with the title DISPLAY MODULE and a border size of 10.&#x20;

`REGION` lets us define the position at which the window will appear and its size. When `NIL`, we can define the region dynamically (by clicking and dragging) like we just did.&#x20;

Predefined regions are useful when we want to create multiple windows of the same type and size. To create a region, we follow the format: `(CREATEREGION LEFT BOTTOM W H)` . LEFT and BOTTOM refer to the pixel distance of the region we're defining from the left and bottom edge of the screen. W and H are the width and height of the window. In the Exec, type:&#x20;

`(CREATEW (CREATEREGION 500 500 300 200) "DISPLAY MODULE" 10)`&#x20;

Do you see your window? Play around with the values to get a feel of the pixel density!&#x20;

<figure><img src="/files/8hXcLR3B9UrPJKc8v0XX" alt=""><figcaption></figcaption></figure>

Try to create a window with no title and border. Can you make one that looks like a button?

{% hint style="info" %}
Regardless of the region set, we can always change the position, shape and size of our existing windows dynamically through its right-click context menu.
{% endhint %}

***

It's quite easy to create different objects in Medley. But ideally, we want a way a to give them short names so we can call them when we want instead of typing out the entire format every time.&#x20;

`(SETQ NAME VALUE)` will let us assign values to variable names. `VALUE` can be a function, a call to create a window, or any snippet of code for which you need a new name. Let's assign a name to our region first. We can use this name to set the region for our window. We'll also give our window a name.

In the Exec, type: &#x20;

1. `(SETQ window-region (CREATEREGION 500 500 300 200))`

Medley is now aware of a new region named `window-region`. We can use this region for any new window we make.

2. `(SETQ display-window (CREATEW window-region "DISPLAY MODULE" 10))`&#x20;

This creates a new variable `display-window` which when called will create a new window at the region `window-region`.

3. We can open or close this window with `(OPENW display-window)` and `(CLOSEW display-window)`.

{% hint style="info" %}
We don't write variable names inside " " because they are not static strings to store but data containers that Medley can open.
{% endhint %}

***

Menus are windows that can have menu-like items and subitems. A cool way to refactor menus is to create a menu with no title and one item which appears and acts like a button.

Menu creations follow the format:&#x20;

`(CREATE MENU TITLE ← "NAME" ITEMS ← '(ITEM1 ITEM2 ITEM3))`

{% hint style="info" %}
You can insert the left arrow in Medley by typing the underscore symbol. If you need a combination of keys for underscore, they should produce a left arrow in Medley.

The left arrow indicates the initial or the default value (on the right) for the field on the left. The field TITLE is initialized with the value NAME and the field ITEMS is initialized with a list of three.&#x20;
{% endhint %}

{% hint style="info" %}
We use `QUOTE` or `'` before a list like `(ITEM1 ITEM2 ITEM3)` because, in Lisp, the first element of a list is normally treated as a function or operator to be evaluated (e.g., `CREATE`, `SETQ`, `+`).&#x20;

By quoting the list using `'(ITEM1 ITEM2 ITEM3)`we tell Lisp to treat it as literal data, not executable code. This prevents Lisp from trying to call `ITEM1` as a function and instead preserves the entire list as a data structure.
{% endhint %}

Creating a menu defines a menu object in the background but doesn't create an instance of it on our screen. To do that we can use: `(MENU NEWMENU POSITION)` where the first `MENU` tells Medley to create a new menu with the name `MENU` at `POSITION` . Example: `(MENU button-menu 700 200)` . This is just an example and won't work because button-menu hasn't been defined yet.

Similar to MENU, we can also use:

* `(ATTACHMENU button-menu display 'TOP 'CENTER)` : Attaches the menu `button-menu` to the window `display` at the top, centered.
* `(ADDMENU button-menu display)` : Adds `button-menu` to the bottom-left corner of `display-window` .&#x20;

In your Exec type:

1. `(SETQ button-menu (CREATE MENU ITEMS ← '("NAVIGATION SYSTEM FAILURE")))`&#x20;

This creates a menu called `button-menu` with no title and one item only.

2. `(ATTACHMENU button-menu display-window 'LEFT 'CENTER)`\
   You should see a button-like window appear on the left edge of the window `display-window`with the text "NAVIGATION SYSTEM FAILED".
3. Right now, the button doesn't do anything. Next, we'll connect a function to the button which can print text to `display-window` .

<figure><img src="/files/ImiDCXvD8k3QhTlrHdk8" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
We can detach and remove this menu with  `(DELETEMENU button-menu display-window)` . This does not delete the menu from memory. You can always repeat Step 2 to reattach the menu.
{% endhint %}

***

Let's create a list of distress calls we can randomly cycle through each time we press our button! In your Exec, type:

{% code overflow="wrap" lineNumbers="true" fullWidth="false" %}

```lisp
(SETQ distress-calls (LIST
"Help! Nav systems compromised. What is lost will never be found."
"Help! Nav systems compromised. Lethal solar flare imminent."
"Help! Nav systems compromised. Stuck in orbit. Planetfall- ETA: 2 cycles."
"Help! Nav systems compromised. Class 3 Destroyer approaching. Contact- ETA: 6 cycles."
"Help! Nav systems compromised. Direction constant. Speed unknown. Debris field ahead. Contact- High."
))
```

{% endcode %}

Now, that we have a list named `distress-calls` , we can set up a function called `nav-sys` that displays a random message from this list to our `display-window` . Next, we'll connect this function to our `button-menu`.

***

We can define a new function with `DEFINEQ` . In your Exec, type:

<pre class="language-lisp" data-overflow="wrap" data-line-numbers><code class="lang-lisp"><strong>(DEFINEQ (nav-sys () 
</strong>    (PRIN1 (CAR (NTH distress-calls (RAND 1 (LENGTH distress-calls)))) 
    nav-display)))
</code></pre>

Let's break down our function:

1. `nav-sys`: Name of function
2. `PRIN1`: for printing to a specific window
3. `CAR`: returns the first element of a list
4. `(NTH list number)`: returns the tail of the specified `list` starting from the specified `number`. So, if we have a list `(A B C D)` and we use `(NTH (ABCD) 2)`, we'll get `(B C D)` as the output.
5. `(RAND value1 value2)`: returns a random value in a range from `value1` from `value2`.
6. `(LENGTH list)`: returns the length of the list.
7. `(CAR (NTH distress-calls (RAND 1 (LENGTH distress-calls))))` :&#x20;
   1. `(RAND 1 (LENGTH distress-calls))` returns a random number between 1 and the total length of the list `distress-calls`.
   2. `(NTH distress-calls` returns the tail of the list starting from the element at that random number.
   3. `(CAR` returns the first element of that tail.
   4. `(PRIN1 ... nav-display)` prints that element to the `nav-display` window, which we will create below.
   5. And of course, `(DEFINEQ (nav-sys ()` gives the name `nav-sys` to our function. For our current function, we have no use for any parameters, so we use an empty parameter list, `()`.

***

Let's delete the button we made before with `(DELETEMENU button-menu display-window)` .

We'll make a new `nav-button` with our `nav-sys` function attached!

In your Exec, type:

{% code overflow="wrap" %}

```lisp
(SETQ nav-button 
(CREATE MENU 
ITEMS ← '("NAVIGATION SYSTEM CHECK")
WHENSELECTEDFN ← (FUNCTION nav-sys)
))
```

{% endcode %}

Our new button has only a minor addition (and a different name).&#x20;

`WHENSELECTEDFN ← (FUNCTION nav-sys)` executes the function `nav-sys` when menu-item (our button `nav-button` ) is selected.

We'll create a new window called `nav-display`:

```lisp
(SETQ nav-display (CREATEW (CREATEREGION 500 500 300 200) "NAV SYSTEM DISPLAY" 10))
```

Let's add our button to our new window next. Type:

`(ATTACHMENU nav-button nav-display 'BOTTOM 'CENTER)`

<figure><img src="/files/lKnsoFq808lHBrguhcQR" alt=""><figcaption></figcaption></figure>

Go ahead and interact with your button!

<figure><img src="/files/gGoUmfXnt4fEPaikcybx" alt=""><figcaption></figcaption></figure>

Is your distress call module working?&#x20;


# Saving Your Work

Medley's File Manager subsystem (also known as the File Package) manages your code in memory and on disk. As we define and change functions, variables, and data structures, the File Manager keeps track of what we have stored in memory and what has been written to external storage. When we load a file in Medley, it parses all the text in the file as Lisp objects and data structures that are ready in memory for the system to use.  As you change your code and data, you can ask the File Manager to show your changes and store them on disk.

#### For saving and loading our work, essential functions and commands (to be typed in the Exec) are:&#x20;

1. `(FILES?)`: Displays the functions, variables, and so on we created or changed and asks for directions for each one: add it to an existing file, add it to a new file, or ignore it.  `(FILES?)` does not update the file on disk, but simply logs what should be saved. <br>

   <figure><img src="/files/fhKglwRZ4lPDFtEpfwuf" alt="" width="425"><figcaption></figcaption></figure>
2. `(MAKEFILE 'filename)`: Saves the changes made to a file by writing it to disk. You can now find the file in your current directory.<br>

   <figure><img src="/files/DPNSeHB50AxwuBlbz2Zx" alt="" width="433"><figcaption></figcaption></figure>

   We can also call `MAKEFILES` to iterate the `MAKEFILE` operation over a list of files. `MAKEFILES` takes an optional list of files as arguments.  Calling it without arguments - `(MAKEFILES) -`  writes all changes to disk.
3. `(LOAD 'filename)`: Loads the file `filename` and its definitions.<br>

   <figure><img src="/files/E2gxDnLbDZ9eMRBV8cQs" alt="" width="406"><figcaption></figcaption></figure>
4. `FILELST` : A variable that contains all files currently loaded in the environment.<br>

   <figure><img src="/files/xTmKKgqltVetp5DHfhu4" alt="" width="407"><figcaption></figcaption></figure>
5. `filenameCOMS`: Gives a list of all definitions contained in the named file.  For instance, you can see all definitions associated with the file `ADDER-FUNCTION` on the variable `ADDER-FUNCTIONCOMS`.<br>

   <figure><img src="/files/klrlAYxdLx0ZlGEYgVts" alt="" width="407"><figcaption></figcaption></figure>

{% hint style="info" %}
You can save multiple Lisp objects to the same file. Try saving all our relevant variables and functions from the previous chapter *(Build Your First Interactive Program)* to a file! We will use and update this file moving forward.
{% endhint %}


# Editing functions with SEdit

Medley's Structure Editor, or SEdit, is a program for editing your code. While the Exec is a central hub for interacting with Medley, SEdit is a dedicated window for making changes to the functions, variables, macros, and data structures we have defined. Remember, all Lisp code is made up of lists, which, regardless of size and shape, can be read by Medley as a data *structure*. Just like the File Manager, SEdit interacts with live Lisp objects in memory. So, objects loaded from files and edited by SEdit still need to be saved using `MAKEFILES` , like we learned in the previous chapter.&#x20;

Let's define an incomplete function we'll want to edit to fix. In your Exec, type:

`(DEFINEQ (new-fn (LAMBDA  (X Y)(X Y)))))`

Right now, our function doesn't do anything. Trying to execute the function with two arguments outputs: "X is an undefined function".&#x20;

We want to make two changes to `new-fn`:

1. Edit the function to output the difference of X and Y instead.
2. Rename the function to a more appropriate name: `differ`

There are several functions that can be used to call/launch SEdit. Refer to Chapter 16 of the IRM to learn more about SEdit's capabilities. For now, we'll focus on the function to edit the definition of a function: `(DF function-name)`

In the Exec, type:\
`(DF new-fn)`

You will see a new window appear on your screen with the title: `SEdit new-fn Package: INTERLISP`

<figure><img src="/files/SPAHDhhGwk0zebt8pUlL" alt=""><figcaption></figcaption></figure>

Click on a part of the code, and you'll see a blinking text cursor appear in place. You can either: Left-click beside a symbol to type new items or left-click on a symbol to edit it. A selected symbol will be underlined. Click the middle-mouse button on a selected object to select different layers of its parents. So, middle-mouse on an item in our list `(X Y)` will first select the entire list and a subsequent click will select the entire function.

We are trying to change this function into one that'll give us the difference between X and Y. Try editing the function to put a minus before X. It should look like:

<figure><img src="/files/CG8rIELW1gG9IZhfpXy4" alt=""><figcaption></figcaption></figure>

Now, click the middle-mouse button on the black title bar to see a new menu appear:

<figure><img src="/files/C7ZVDSfauqgDJgtxHHfb" alt="" width="376"><figcaption></figcaption></figure>

Select the option Done, Compile, and Close to update our function. We are going to test our new function soon. But first, let's update the name to match what it does.&#x20;

We can use the `RENAME` function to change the name of a symbol - for example, the name of a function. The general form is: `(RENAME old-function-name new-function-name)` .&#x20;

In the Exec, type:

`(RENAME 'new-fn 'differ)`

Our function name has now been changed from `new-fn` to `differ` . Try out the function and see if it works:

<figure><img src="/files/tMZZsZOUTmRvtXX3GV0c" alt=""><figcaption></figcaption></figure>

#### **Comments**

We can add comments in SEdit, using a semicolon.&#x20;

Three levels of comments are supported in Medley. According to the Interlisp Reference Manual:

> Single-semicolon comments are formatted at the comment column, about three-quarters of the way across the window. Doublesemicolon comments are formatted at the current indentation of the code they are in. Triple semicolon comments are formatted against the left margin. The level of a comment can be increased or decreased by pointing after the semicolon, and either typing another semicolon, or backspacing over the preceding semicolon.

#### Useful Key Combinations

| Operation                    | Input/Key Combination                                                                                                                                                                                     | Description                                                                                                                     |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Copy and Paste Selected Text | Left-click and move the cursor to the position where you want the copied text to be moved/pasted to. Hold SHIFT while selecting (Left or Middle mouse button) the text to copy. Let go of SHIFT to paste. | Inserts the selected text at the text cursor position.                                                                          |
| Cut and Paste Selected Text  | Hold CTRL + SHIFT while making a mouse selection. Let go to paste.                                                                                                                                        | Combines copy and delete actions, moving the selected text to the text cursor position.                                         |
| Undo Deletion                | Alt + U (Windows and Linux), Option + U (Mac OS)                                                                                                                                                          | Undos recently deleted text.                                                                                                    |
| Delete Selected Text         | Hold CTRL while making a mouse selection (Left or Middle button)                                                                                                                                          | Deletes the selected text.                                                                                                      |
| Parenthesize                 | <p>Alt/Option+ ( </p><p>or Alt/Option + )</p>                                                                                                                                                             | Encapsulates the selected text in parenthesis.                                                                                  |
| Delete Backward (Word/Atom)  | <p>Control-W<br><br>In some environments, most notably Medley Online, Control-W closes the current browser tab or window. This behavior can be neutralized with Alt/Option+Control+W.</p>                 | Deletes the previous atom or structure. If the cursor is inside an atom, it deletes backward only to the beginning of the atom. |
| Find Forward                 | Alt/Option + F                                                                                                                                                                                            | Finds the next occurrence of a specified structure (or the currently selected structure).                                       |


# The File Browser

The File Browser is a Medley tool that makes it easy to manipulate files on your disk. It is distinct from the File Manager ("File Package"), which coordinates Lisp definitions in memory and their representation on disk.  The File Browser is like the macOS Finder, Windows Explorer, or Gnome's Nautilus.

To run it, select File Browser from the background menu. Hold down the left mouse button and drag to shape the window:

<figure><img src="/files/96MSUEvxEK9zeXAKS3We" alt=""><figcaption></figcaption></figure>

To view all the files in a directory, type \* and press Enter, in the File group description prompt:

<figure><img src="/files/G1hDuep4JaW6Pdi3GC8V" alt=""><figcaption></figcaption></figure>

You can also type a specific file name to work only with that one.

<figure><img src="/files/bEruAShpTHStt3f3zfWw" alt=""><figcaption></figcaption></figure>

To select a file, use the left mouse button; to select multiple, use the middle mouse button. A file is selected when a solid right-pointing arrow appears to its left. To deselect an already chosen file, hold down the Ctrl/Command key while pressing the middle mouse button.

<figure><img src="/files/pJM4qSUQ3BqzhzqS9V5f" alt=""><figcaption></figcaption></figure>

Once one or more files have been selected, you can perform the operations available to you through the permanent menu FB Commands attached on the right.

| Command   | What Does it Do                                                                                                                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Delete    | Marks selected files for deletion (crossed out in the list). Files aren’t removed until you use Expunge.                       |
| Undelete  | Restores any files previously marked for deletion.                                                                             |
| Copy      | Copies selected files. You’ll be prompted for a full destination filename (for one file) or a directory (for multiple).        |
| Rename    | Moves or renames selected files. You’ll be prompted, for a new filename (single) or a target directory (multiple).             |
| Hardcopy  |                                                                                                                                |
| See       | Opens the selected file in a new read-only window for viewing.                                                                 |
| Edit      | Opens the selected file in the Medley editor. For Lisp files, only the `FILECOMS` list (functions, variables, etc.) is edited. |
| Load      | Loads selected file(s) into the Medley environment.                                                                            |
| Compile   | Compiles selected file(s) from disk. If changes were made, use `(MAKEFILE 'filename)` before compiling.                        |
| Expunge   | Permanently deletes all files currently marked for deletion.                                                                   |
| Recompute | Refreshes the directory listing to reflect any recent changes (e.g., new file versions).                                       |


# Debugging

Part of what sets Medley apart is a collection of dedicated functions and features to help us debug our programs.

#### **FIX and ED**

`FIX line-number` :

`FIX` lets us edit whatever we typed at a specific line number. It's useful when we want to make an immediate change.

<figure><img src="/files/0kfcbwdFksTTz8pScG5o" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Remember, we can refer to line numbers from any Exec. You might find it helpful to work with multiple smaller Execs, each focusing on a unique function of the larger program.
{% endhint %}

Back in the SEdit chapter, we learned about editing the definition of a function with `(DF function-name)`, which Medley internally translates to `(ED 'NAME '(FUNCTIONS FNS :DONTWAIT))`. You don't need to use this expanded form, but it's good to know what goes on in the background.&#x20;

&#x20;`(ED 'function-name)`

While `DF` is for editing functions only, `ED` is the default editor function we can use to edit any File Manager object, including function definitions, variable values, property lists, or file package commands through SEdit.

{% hint style="info" %}
The `:DONTWAIT` statement in DF’s call to ED lets SEdit return immediately, so the Exec doesn’t stall after starting an edit. This means you can continue working in the Exec while making edits in SEdit and changes take effect as you make them, without waiting for a completion command.&#x20;

Try both DF and ED to edit a function. Does one of them let you switch to the Exec freely? Which one restricts you to SEdit?
{% endhint %}

***

#### **INSPECT**

At times, you will define variables containing values more complex than an atom. As our programs grow larger, we might want to take a quick look at the contents of these variables in an organized, tabular format without opening an editor like SEdit:

<figure><img src="/files/k7eo8TUJspLAiHdYBoKg" alt=""><figcaption></figcaption></figure>

`INSPECT`allows us to do exactly that:

<figure><img src="/files/Ku11aJsK7WKei30H46Ll" alt=""><figcaption></figcaption></figure>

Select Inspect from the menu, and a window appears with two columns. The first column displays the numbered positions of the list items, and the second column displays the item in that position.

<figure><img src="/files/1VxgujxdrFLi44MKUYK0" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Notice how we use a quote (') before the variable name when we need to edit the definition of the variable. The system does not need to evaluate or understand the contents. It only needs to display the contents for us to make changes. Quote (') tells Lisp not to evaluate or "run" what follows.\
\
But when it comes to Inspect, we do want the system to understand the contents of the list so it can organize and display it neatly for us to review. No quotes for that operation!
{% endhint %}

***

#### BREAK

`BREAK` sets a breakpoint, letting you halt a function midway and inspect what might be going wrong in a dedicated Break Window. We can break and unbreak entire functions. This is handy when your function is huge, complex, and expensive to compute. We can also insert conditional breakpoints inside a function that breaks the function if certain criteria are met. This is useful when you want to ask questions about the flow of data through your program. Or when you want your program to stop its operation if (as opposed to printing the state and continuing).

{% hint style="info" %}
If you're stuck in an infinite loop or just want to break out of the current running function, use **Ctrl + B.**
{% endhint %}

In a COND, use `(ERROR "Something meaningful to print about the break")` to trigger a break at a when you detect an error condition.

Let's define a function that prints out the factorial of any given number.

<figure><img src="/files/JQla8HdBOBCu5hRV37gH" alt=""><figcaption></figcaption></figure>

Factorials can be quite large. Suppose we want to limit the program so that only factorials of numbers no greater than 10 are printed. Pull up SEdit to edit the function `factorial`. Add another condition to the COND block:&#x20;

`((GREATERP X 10) (ERROR "This number is too large. X should be less than 11."))`

This tells Medley to break the function if X is greater than 10.

<figure><img src="/files/VMKbxh6Qd59WGXOzvLXk" alt=""><figcaption></figcaption></figure>

Once the new function is compiled, try a few different values to test if it's working as intended.&#x20;

For `(factorial 11)`, or any number larger than 10, you should see the break window appear with your message:

<figure><img src="/files/tpIVtVbxUhb3lx9YtaTH" alt=""><figcaption></figcaption></figure>

***

#### TRACE

When your program is not acting as intended, the final output might not necessarily reveal what you need to fix. Being able to look at the internal calculations your functions are making and what output they generate at every step is a useful feature, and TRACE lets us do exactly that.&#x20;

Let's trace our factorial function.

<figure><img src="/files/WqvFMAfF2vV6loycVrjT" alt=""><figcaption></figcaption></figure>

After we've traced a function with `TRACE function-name`, executing the function will open a Trace-Output window:

<figure><img src="/files/tPj1UocTfGmLMfDzjL8s" alt=""><figcaption></figcaption></figure>

To stop tracing a function use `UNTRACE`:

<figure><img src="/files/yfDTaVgjMaevfxKU8Wqk" alt=""><figcaption></figcaption></figure>

***

#### ADVISE

As our programs grow more complex, we might not want to change the original code when we need to make a small, temporary change. `ADVISE` is a Medley feature to modify the behavior of a function by wrapping code "around" that function without having to edit it. It's also useful when you're working with someone else's code and want to preserve the integrity of their code.

The `ADVISE` function takes four arguments:\
`(ADVISE function-name WHEN WHERE WHAT)`

`WHEN` specifies when in the function call should the advised code be executed. Before the function, after the function, or should it replace the function's body entirely by executing around it? `WHEN` has three valid parameters: `BEFORE`, `AFTER`, `AROUND`

`WHERE` specifies where in a list of advice the current advise should be inserted. `WHERE` has two valid parameters: `FIRST` or `TOP` and `LAST` or `BOTTOM` or `END`. We can use `NIL` for `WHERE` unless we have multiple advises. If `WHEN` is `AROUND`, `WHERE` is considered NIL.

`WHAT` is the advised code to run.

Let's advise our factorial function to check if X is a string or a number:

<figure><img src="/files/kQdX2nyMLJMZJfmKraTo" alt=""><figcaption></figcaption></figure>

Now, when we execute `factorial`, we see:

<figure><img src="/files/2floS0kmvQpc0wudc4Es" alt=""><figcaption></figcaption></figure>

We can remove advice from a function using `UNADVISE`:

<figure><img src="/files/0SuZbu3GP7xrSw1Pw8uP" alt=""><figcaption></figcaption></figure>

Try adding two ADVISEs to a new function. One should appear before and one after the function is executed.

<figure><img src="/files/FZ8xcDGRtCAkI2PmnnAG" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
!VALUE can be used to access the final value of the function. \
PROGN executes what follows sequentially. We'll learn more about it in the next chapter.
{% endhint %}


# TEdit, the WYSIWYG Text Editor

TEdit is Medley's native text editor. You can use it to create and edit formatted or plain text files. Several formatting options to change the appearance of the text and the page, including features like inserting images, are available.

To open TEdit, hold down the right mouse button in an empty area on the screen and select TEdit from the menu that appears.

<figure><img src="/files/XoWu9xW1cUQ8EVH7EgMF" alt=""><figcaption></figcaption></figure>

Click, drag, and let go to create your editor window.  You can start writing:

<figure><img src="/files/QTrrTn086tfCt6WvTzmZ" alt=""><figcaption></figcaption></figure>

To change the cursor's position, left-click at the new position or drag while holding down the left mouse button near existing text. Use the middle mouse button instead if you want to select a word. To highlight and select larger segments of the text, hold down the right mouse button and drag over the intended section. The region to the left of the text is special: If you left-click there, you select the line. If you middle-click there, you select the paragraph. To deselect, left-click on an empty space inside the editor.

The white bar at the top is the prompt pane, which will display information about TEdit as we take certain actions.

Press and hold the middle mouse button on top of the black title bar of the TEdit window. This menu should appear:

<figure><img src="/files/zIVFGOAka16aWEDuiJPn" alt=""><figcaption></figcaption></figure>

You can change the appearance of selected text just like modern text editors. There are a couple of ways to do that, but the easiest is to pull up the TEdit Buttons menu. From the menu shown above, select Buttons. You should see the following menu appear at the bottom of your screen:

<figure><img src="/files/pTNxHeWum9ycjDrdbChx" alt=""><figcaption></figcaption></figure>

Try giving your text a different format. When you left-click on any one of these buttons, you'll see a brief description of the changes above the title bar.

<figure><img src="/files/4ltFX1wT1iX7kpEAL3n3" alt=""><figcaption></figcaption></figure>

To set the format to the document's default, click the Defaults button.

<figure><img src="/files/ZVLpsLJdVKTSzv0v4M82" alt=""><figcaption></figcaption></figure>

#### Persistent Menus: Apply, Show, and Neutral

We can access more functions through the Expanded Menu. These menus are persistent: they will stay at the position in which they appear until we close them. Select the Expanded Menu by hovering over it in the menu and letting go of the mouse button. A new panel entitled TEdit Menu should appear above your TEdit window.

<figure><img src="/files/9wzMIJVZFqmjKfDQQhSs" alt=""><figcaption></figcaption></figure>

Options like Page Layout, Char looks, and Para looks will open their respective menus on top of the expanded menu.

<figure><img src="/files/48MQBUu2pAEy2SD2lipY" alt=""><figcaption></figcaption></figure>

The expanded menu gives us a lot of options to change the look and layout of our text and the page. Except for APPLY, SHOW, and NEUTRAL, in the persistent menu, some menu items have three states (On, Off, Neutral) and some have two states (On and Neutral):

{% hint style="info" %}
These three states can either be applied or removed from your selected text or to your page. Remember, you can select a piece of text by using the left mouse button for selecting letters, the middle mouse button for selecting words, and holding down and dragging the right mouse button over larger chunks of text like sentences and paragraphs.&#x20;
{% endhint %}

On:

A left-click selects and turns on a menu item in the persistent menus. This change is now ready to be applied to the selected text.

<figure><img src="/files/yAZaCbrKmChWTIXxvReL" alt=""><figcaption></figcaption></figure>

Off:

Another left-click shows an oblique line across the option, indicating that the option is now off. The change is now ready to be removed from the selected text.

<figure><img src="/files/erO7BAswssBcBrzIHJtp" alt=""><figcaption></figcaption></figure>

Neutral:

Another left-click removes either the on or off state and returns the option to a neutral state, indicating that this change is no longer in effect.&#x20;

<figure><img src="/files/mNh15sWsc5x6ZjIbDzcQ" alt=""><figcaption></figcaption></figure>

APPLY:

This applies the changes to the selected text.

SHOW:

This shows which options have been applied and turned off for the selected text. It's useful when we've applied multiple changes to our text and/or our page.

NEUTRAL:

This returns all active and selected menu items to neutral. It's the default state of the persistent menus.

{% hint style="info" %}
Two-state menu items, like the fonts, cannot be turned off. We simply switch to a different option than the currently active one and apply it.
{% endhint %}

#### Reading TEdit Files

#### Opening an existing TEdit file:

From TEdit's context menu, we click on Get.

<figure><img src="/files/XSbL4UDKguoqEEwIlEEn" alt=""><figcaption></figcaption></figure>

Then type the file name.

<figure><img src="/files/NZfDezRLdRomDxqdMgiF" alt=""><figcaption></figcaption></figure>

#### Opening a plain text file in TEdit:

From TEdit's context menu, we can expand Get and select Unformatted Get.

<figure><img src="/files/yUl5fLMAwij9s76jdlgj" alt=""><figcaption></figcaption></figure>

Just like Put, we'll be prompted for a file path, which for the online version of Medley can just be the file name.

<figure><img src="/files/kK2pHY0NqLbgs50AqUai" alt=""><figcaption></figcaption></figure>

The file we saved earlier, plain-text.txt, has now been imported to TEdit for us to edit.

<figure><img src="/files/Db13tAMP9rgAIWECgVvt" alt=""><figcaption></figcaption></figure>

#### Saving TEdit Files

We can save ("put") our text as formatted text, plain text, or render ("hardcopy") it to a PDF file.&#x20;

To create a PDF:\
Hold down the right mouse button on top of the black title bar. Expand the menu item Hardcopy and select File.

<figure><img src="/files/dXo2HsQBGhQXmR237Bbd" alt=""><figcaption></figcaption></figure>

The following window will appear, asking for a file name:

<figure><img src="/files/89fpI5yK8crQzsGDHw3g" alt=""><figcaption></figcaption></figure>

Type your file name, making sure it ends with .pdf.

<figure><img src="/files/TmNEpQmQKMc4oWX46aYq" alt=""><figcaption></figcaption></figure>

To save a plain text file:

Hold down the middle mouse button on top of the black title bar. Expand the menu option Put and select Plain-Text.

<figure><img src="/files/OvU2tYywoQxHNcSXYSyr" alt=""><figcaption></figcaption></figure>

You'll see a prompt appear above the title bar, asking for the path to save the file.&#x20;

<figure><img src="/files/iYRheTGtx2wYPQrpmtDP" alt=""><figcaption></figcaption></figure>

We can get away with writing just our file name and extension. Medley will store it in the connected directory.

<figure><img src="/files/FFF8tX2y2EjLFVzaWiLU" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/kOvqHPusulHi9PM7mLFN" alt=""><figcaption></figcaption></figure>


# Drawing and Displaystreams

In *Build Your First Interactive Program,* we learnt how to make our own windows. In Medley, we can create a special window for drawing, somewhat similar to a pixel art editor- a bitmap editor. A bitmap is a rectangular array of pixels.

The form `(BITMAPCREATE width height)` creates a bitmap in the background, but it cannot be seen till we assign a variable name to it and edit it. We can edit a bitmap using:

`(EDITBM bitmap-name)`

In an Exec, type:

`(SETQ my.bitmap (BITMAPCREATE 40 40))`

and then:

`(EDITBM my.bitmap)`

<figure><img src="/files/sPD1BU9jDxc1xCYjfVzN" alt=""><figcaption></figcaption></figure>

Your cursor will now display the outline of the window you created. Your Prompt Window displays: *Indicate the position for the Bitmap Edit Window*. Left-click on an empty space in your workspace to place your bitmap editor.<br>

<figure><img src="/files/mMMT8llfQikVUWsXrv9A" alt=""><figcaption></figcaption></figure>

To draw, hold down on your left mouse button, and to erase, hold down your middle mouse button.

To save your bitmap, hold down the middle mouse button in the solid gray box in the upper-center area. A menu will appear. While holding down the middle mouse button, place your cursor on top of "OK" and let go. Your work will be saved, and the window will close. The next time you edit your bitmap, you'll see what you previously drew.

<figure><img src="/files/B3aLeoPd6gaJxFWHpwQA" alt=""><figcaption></figcaption></figure>

***

Bit Block Transfer or `BITBLT` is a method for displaying a bitmap inside another bitmap or a window.

`BITBLT` has the following parameters:

`(BITBLT sourcebitmap sourceleft sourcebottom destinationbitmap destinationleft destinationbottom width height sourcetype operation texture clippingregion)`

`sourcebitmap`: The bitmap to be moved into the destinationbitmap

`sourceleft`: A number, starting at 0 for the left edge of the sourcebitmap, that tells BITBLT where to start moving pixels from the sourcebitmap. For example, if the leftmost 10 pixels of sourcebitmap were not to be moved, sourceleft should be 10. The default value is 0.

`sourcebottom`: A number, starting at 0 for the bottom edge of the sourcebitmap, that tells BITBLT where to start moving pixels from the sourcebitmap. For example, if the bottom 10 rows of pixels of sourcebitmap were not to be moved, sourcebottom should be 10. The default value is 0.

`destinationbitmap`: The bitmap that will receive the sourcebitmap. This is often a window (actually the bitmap of a window, but Interlisp takes care of that for you).

`destinationleft`: A number, starting at 0 for the left edge of the destinationbitmap, that tells BITBLT where to start placing pixels from the sourcebitmap. For example, to place the sourcebitmap 10 pixels in from the left, destinationleft should be 10. The default value is 0.

`destinationbottom`: A number, starting at 0 for the bottom edge of the destinationbitmap, that tells BITBLT where to start placing pixels from the sourcebitmap. For example, to place the sourcebitmap 10 pixels up from the bottom, destinationbottom should be 10. The default value is 0.

`width`: How many pixels in each row of sourcebitmap should be moved. The same amount of space is used in destinationbitmap to receive the sourcebitmap. If this argument is NIL, it defaults to the number of pixels from sourceleft to the end of the row of sourcebitmap.

`height`: How many rows of pixels of sourcebitmap should be moved. The same amount of space is used in destinationbitmap to receive the sourcebitmap. If this argument is NIL, it defaults to the number of rows from sourcebottom to the top of the sourcebitmap.

`sourcetype`: Refers to one of three ways to convert the sourcebitmap for writing. For now, just use ’INPUT.

`operation`: Refers to how the sourtebitmap gets BITBLT’d on to the destinationbitmap. ’REPLACE will BLT the exact sourcebitmap. Other operations allow you to AND, OR or XOR the bits from the sourcebitmap onto the bits on the destinationbitmap.

`texture`:Just use NIL for now.

`clippingregion`: Just use NIL for now.

{% hint style="info" %}
Try displaying your new artwork in a new window. Refer to previous chapters if you need a refresher on windows.
{% endhint %}

***

Till now, we've learnt how to create windows with a predefined size, border, and title. But there's a simpler way to make a window:

In an Exec, type: `(SETQ my.window (CREATEW)`

Your cursor will change. You can now click, drag, and create a new window of any size. You can refer to this window just like any other using the name you set, which is my.window for this example.

<figure><img src="/files/h0jZRW8pNN5XWvbtQCp4" alt=""><figcaption></figcaption></figure>

Windows are displaystreams. A display stream is simply a place to display. They determine what is displayed and where. We've learnt to draw with a dedicated bitmap editor but did you know we can also draw on a disaplystream- a window with code?

There are four primary functions for drawing to a displaystream:

**DRAWLINE**: `(DRAWLINE x1 y1 x2 y2 width operation stream color dashing)`

Example: `(DRAWLINE 10 15 100 150 5 ’INVERT my.window)`

<figure><img src="/files/kNzP0TbLndtzxBajejfv" alt=""><figcaption></figcaption></figure>

**DRAWTO**: `(DRAWTO x y width operation stream color dashing)`

Example: `(DRAWTO 120 135 5 ’INVERT my.window)`

<figure><img src="/files/CImnwif265iOs2A9xC3q" alt=""><figcaption></figcaption></figure>

**DRAWCIRCLE**: `(DRAWCIRCLE centerx centery radius brush dashing stream)`

Example: `(DRAWCIRCLE 150 100 30 ’(VERTICAL 5) NIL my.window)`

<figure><img src="/files/B5u3IL0fBZBnPD2H3nhb" alt=""><figcaption></figcaption></figure>

**FILLCIRCLE**: `(FILLCIRCLE centerx centery radius texture stream)`

Example: `(FILLCIRCLE 200 150 10 GRAYSHADE my.window)`

<figure><img src="/files/fz5O0fzoIKQV2aYRhqrv" alt=""><figcaption></figcaption></figure>


# Making a Graph with Grapher

Grapher is a small program for making graphs in Medley. There are a few ways to do that, but for now, we'll stick to the easiest method.&#x20;

The function SHOWGRAPH displays graphs and allows you to edit them. The parameters of SHOWGRAPH are:

`(SHOWGRAPH graph window lefibuttonfn middlebuttonfn topjustifyflg alloweditflg copybuttoneventfn)`

We won't go over what all the parameters do in this primer. Instead, let's try making our first graph.&#x20;

Start by declaring a variable name. In an Exec, type:

`(SETQ my.graph NIL)`

Now, let's create a window which will serve as a graph editor:

`(SHOWGRAPH my.graph "My Graph" NIL NIL NIL T)`

<figure><img src="/files/vWLJqqRudbKlJstQRkdd" alt=""><figcaption></figcaption></figure>

Place your graph in an empty space. If you want to change the size and shape of the window, hold down the right mouse button on the title bar just like you would with any window, place your cursor on the menu item Shape, and let go.

Let's start building our graph by adding and connecting nodes. In the white space in the graph editor window, hold down your right mouse button, and a different menu will appear with context-relevant options to choose from.

<figure><img src="/files/d273dW56It4GQ2xwhDho" alt=""><figcaption></figcaption></figure>

Select Add Node, and you'll see a small window appear on top of the graph window with the title Node label?

<figure><img src="/files/zUj1oiCfJlKLgUKQOLT7" alt=""><figcaption></figcaption></figure>

This is the label of your node. Type Node ONE for now and press Enter. You'll see a node attached to your cursor. To place the node, left-click on any empty space in the window. Your node will appear with the label you set.

<figure><img src="/files/DPI5FCBVJXC6wSAgdVLf" alt=""><figcaption></figcaption></figure>

Add three more nodes with the labels One A, One B, and One C, respectively.

<figure><img src="/files/zuHutyzx568nADxd9h0Q" alt=""><figcaption></figcaption></figure>

Let's link these nodes. Bring up the main menu for the graph window and select Add Link.

<figure><img src="/files/MhyhNNBfGkb9ybWF0NlI" alt=""><figcaption></figcaption></figure>

Once you select Add Link by placing the mouse cursor on top of it and letting go, you'll notice your Prompt Window is asking From?

<figure><img src="/files/gJHrvbEAfmuSMjUB66ip" alt=""><figcaption></figcaption></figure>

Left-click on the node from which the link will be drawn.

Your Prompt Window will now ask To?

Left-click on the node to which the link will be drawn.

Your Prompt Window now tells you which link you just added.

<figure><img src="/files/XSsdVbeaNRlqWONNtOJK" alt=""><figcaption></figcaption></figure>

You'll notice a straight line from Node ONE to ONE A in your graph window. Add two more links from Node ONE to ONE B and to ONE C.

<figure><img src="/files/GxdN6qFVuh2F8R1TD28t" alt=""><figcaption></figcaption></figure>

You can also move and delete nodes. To move a node, select Move Node from the menu. Once the menu disappears, hold down the left mouse button on the node you want to move, drag it to a new location, and let go.&#x20;

To delete a node, select Delete from the menu and then the node to be deleted.

{% hint style="info" %}
Your prompt window always displays relevant information to whatever you're trying to do. If you're unsure how to proceed, look at the prompt window for instructions.
{% endhint %}


# Additional Resources

You've reached the end of this primer. But your journey with Medley Interlisp has only begun!

We have an excellent selection of resources of all types for you to explore, whether it's cool things you can do with Medley and Interlisp or fascinating chunks of history you can read and watch.

* [Running and installing Medley](https://interlisp.org/software/install-and-run/) on different operating systems.
* [All documentation](https://interlisp.org/software/using-medley/): old, new, for beginners and advanced users.
* [Use Medley online](https://interlisp.org/software/access-online/) without having to install anything.
* [Frequently asked questions](https://interlisp.org/project/faqs/)
* Medley Interlisp Project, [YouTube Channel](https://www.youtube.com/@Interlisp)
* The [discussion board on GitHub](https://github.com/orgs/Interlisp/discussions) is for general discussions and questions on the Medley environment, the Interlisp language, and Lisp development on the Medley system.
* An [article ](https://parentheticallyspeaking.org/articles/bicameral-not-homoiconic/)(not by us) laying out the debate around Lisp's homoiconicity.
* [More useful key combinations](https://interlisp.org/software/using-medley/keystrokes/).
* A [glossary of terms](https://interlisp.org/history/glossary/) you'll come across as you go through the bibliography.
* A [timeline of Medley and Interlisp history](https://interlisp.org/history/timeline/) provides a comprehensive overview.
* [A paper by Eleanor Young et al.](https://interlisp.org/documentation/young-ccece2025.pdf) that discusses Medley's revival. Presented and accepted for publication at the 2025 IEEE Canadian Conference on Electrical and Computer Engineering.
* [Get involved with Medley's progress and development.](https://interlisp.org/project/getinvolved/) Talk to the team. Connect with us on social media.
* [Latest News and status reports](https://interlisp.org/project/status/)
* [Words from the team](https://interlisp.org/project/stories/)


