Logo Revisited

Jul 25th, 2023

 

Contents

Elementary School

If you are of a certain age, at some point in your elementary school career someone may have introduced you to a new friend. This new friend was a turtle who lived in this incredible machine called a computer. You probably thought, as I did, that it was odd to call this creature a turtle since it was really just a triangle.

Logo-turtle

This turtle was able to respond to simple commands such as FORWARD 10 and RIGHT 90 which would cause your turtle to move. As it moved, it would draw a line from its old location to its new location. It acted as though it had a marker pressed to paper. You could even teach it new tricks:

TO SQUARE :SIZE
REPEAT 4 [ FORWARD :SIZE RIGHT 90]
END

Logo-square

Now you could draw squares, or even better, you could draw a bunch of squares: REPEAT 30 [SQUARE 30 RIGHT 12]

Logo-many-squares

The language was simple, you could play with it, and you could draw repeating geometric shapes with it, but it was so much more than we were led to believe!

Logo as a Language

Let’s take a moment and just think about Logo as a programming language in its own right. First and foremost, Logo is a multi-paradigm language. In the typical use case, turtle graphics, the language appears to be procedural. If all you have is this superficial view of the language, you may believe that it has globally scoped variables with local parameters to procedures but this is not the case. Logo is closer to being a functional programming language. You may be surprised to learn that Logo has the following functional characteristics:

  • Logo procedures (I.e. functions) are first-class objects.
  • Logo is dynamically scoped.
  • Function evaluation is the fundamental operation in Logo, including all of its control structures.
  • Logo has tail recursion optimization.

As with a language, Logo has a type system. There are two fundamental types of objects in Logo: words and lists. A word is just any collection of characters, and a list is a series of words or lists enclosed in square brackets. Generally, words are delimited by spaces though backslashes can be used to get literal characters that would normally be delimiters. Consider the following program:

PRINT [Hello, world.]

This would, of course, print the message “Hello, world.” In this case, the list consists of the words “Hello,” and “world.” Numbers are also words. There is a little bit more to the syntax of words, but I think I will cover those as they come up in this little reflection. For now, let’s look at some more aspects of the language.

Exploring Logo’s Functional Features

As I mentioned before, Logo tends toward being a functional language. One way to demonstrate this is to take a look at how functions are represented internally. If we run the following:

SHOW TEXT "SQUARE

we get the following output:

[[SIZE] [REPEAT 4 [ FORWARD :SIZE RIGHT 90]]]

What we find is that a procedure is a list containing two elements. First, there is a list of the local parameters to bind. Second, there is a list of words to evaluate. Clearly, such an object can be programmatically created, and we could even manually bind it to a symbol. In fact, the more formal way to create the square method would be to use the DEFINE primitive:

DEFINE "SQUARE [[SIZE] [REPEAT 4 [ FORWARD :SIZE RIGHT 90]]]

Now, if you are into functional programming, this probably has very strong Lisp vibes for you. This is not a coincidence. Lisp was a major influence in the design of Logo. An apt description, which I have read in too many places to find an original citation, is that Logo is like Lisp without parenthesis. Another Lisp-like aspect of the language is the distinction between quoted and unquoted words. A quoted word is left as its literal text while an unquoted word is evaluated. (All words in lists are automatically quoted.)

In addition to functions, lists may also be run. This approaches the ability to write anonymous functions, though typical Logo implementations lack lambda expressions. Being able to run lists, coupled with dynamic scoping, will serve the same purpose. Consider the following:

TO SPIN :N :FUN
LOCAL "ANGLE
MAKE "ANGLE 360 / :N
REPEAT :N [RUN :FUN RIGHT :ANGLE]
END

TO SPIRAL :SIZE
SPIN 30 [SQUARE :SIZE]
END

Running SPIRAL 30 will produce the same square spiral I drew earlier. Now, you may ask “So what?” regarding the scoping. What is going on though is that scope nesting is done by caller callee. SIZE is a local variable of SPIRAL. When FUN is run in SPIN, it can access the local variable from the caller. This is how Logo scoping works.

As mentioned before, function evaluation is basically the only operation in Logo. Take for instance the REPEAT control structure. This is just a Logo procedure that has a signature something like this REPEAT :N :INSTRUCTIONLIST. Of course, we do not know the names of the inputs to the REPEAT function, but it certainly takes two arguments: the number of repetitions and the list of instructions to repeat. In fact, there is nothing magical about REPEAT. It could be written in terms of other Logo primitives. We could do something like this:

TO MY.REPEAT :N :INSTRUCTIONLIST
IF EQUALP :N 0 [STOP]
RUN INSTRUCTIONLIST
MY.REPEAT :N-1 :INSTRUCTIONLIST
END

Note that this is a loop built with tail recursion; how very Lispy.

We could use this same technique to add a while loop to Logo. The “USEFUL.TOOLS” file on the Apple Logo 2 disk contains just such a function:

TO WHILE :CONDITION :INSTRUCTIONLIST
TEST RUN :CONDITION
IFFALSE [STOP]
RUN :INSTRUCTIONLIST
WHILE :CONDITION :INSTRUCTIONLIST
END

This is, of course, only possible with the dynamic scoping that Logo provides as that ensures that the variables referenced in the instruction list will behave pretty much as expected. This also means that Logo is almost entirely extensible because it is just a language of function composition and evaluation. At least, that is what it is at its most formal level (more on that in a bit.)

Exploring Logo’s Imperative Features

As I mentioned earlier, Logo is a multi-paradigm language. You may be surprised to learn that Logo has some raw imperative features as well. Most notably, you can label lines and jump to them. This is implemented in pretty much the same way as it is in C. The jump and destination must be part of the same procedure. Beyond that, you can code in a purely imperative way. Take, for instance, the following procedure which implements a guessing game in much the same way we might write this in a language like BASIC:

TO GUESSING.GAME
LOCAL "NUM
LOCAL "GUESS
LOCAL "SCORE
LABEL "START
MAKE "NUM RANDOM 100 + 1
MAKE "SCORE 0
LABEL "GUESS
TYPE [GUESS A NUMBER BETWEEN 1 AND 100:]
MAKE "GUESS READWORD
IF NOT NUMBERP :GUESS [GO "INVALID]
IF OR :GUESS < 1 :GUESS > 100 [GO "INVALID]
MAKE "SCORE :SCORE + 1
IF :GUESS = :NUM [GO "WIN]
IF :GUESS < :NUM [PR [TOO LOW.]]
IF :GUESS > :NUM [PR [TOO HIGH.]]
GO "GUESS
LABEL "INVALID
PR [INVALID GUESS. PLEASE TRY AGAIN.]
GO "GUESS
LABEL "WIN
PR SE [CORRECT! NUMBER OF GUESSES:] :SCORE
TYPE [PLAY AGAIN \(Y\/N\)?]
IF READWORD = "Y [GO "START]
END

Logo-guess

This is not the elegance one might expect out of a functional language. Of course, there are reasons this ability to jump around is included. First, having the imperative paradigm there makes it a bit easier to teach other aspects of programming. However, there is a more practical reason. Simply put, this is the only iterative primitive in the language and sometimes iteration is needed to make code run faster. So sometimes, a serious Logo programmer may just need this capability.

Another interesting point of this (mostly) functional language is that it has two aspects. First, there is the formal aspect. Formal Logo is simply Lisp without parens! This means it has only prefix function notation and evaluation. So, for instance, to work out the answer to “2+3*4”, we would need to execute:

PRINT SUM 2 PRODUCT 3 4

Of course, this would be rather unfriendly for beginners. So instead, Logo contains several kludges which make it friendly to use. We could perform the above operation as:

PRINT 2 + 3 * 4

Or, by employing abbreviations:

PR 2 + 3 * 4

Informal Logo, the one that the interpreter really processes, has a few operators and performs expression parsing. This is why we can use both formal predicates: EQUALP :X 5 as well as infix operators :X = 5 to perform comparisons. Also, even the variable syntax is an abbreviation. :X is formally THING "X. The procedure headers TO PROC.NAME :INPUT are similarly a friendly statement for DEFINE "TO [[INPUT] [...]] .

This also reveals a little something about Logo’s symbol table handling. Essentially, there are multiple lists of bindings. There is a “thing” list for variables, a “function” list for defined words, and a “label” list for labeled lines. This means that you can have one of each. The same literal word could refer to a procedure, a variable, and a label.

These small deviations from the functional formalism are, in my opinion, the secret to what makes Logo such an intuitive language. It also gives you a powerful environment while still making it possible to write readable code. That is, of course, provided you are disciplined enough to not create recursive spaghetti monsters!

So what happened? A brief history of Logo.

Logo was created in 1967 by Wally Feurzeig, Seymour Papert, and Cynthia Solomon at Bolt Beranek and Newman Inc. BBN is a research company in Cambridge Massachusetts that both employed and consulted with many of the big names in artificial intelligence from MIT. This is evident in the influence which Lisp had over the Logo language. When the creators of Logo sought to create a mathematical playground for children, they structured it as a similar language. The first Logo interpreter was coded in Lisp. At some point during the development of the project, Seymour Papert was introduced to a robot called the tortoise. Realizing that Logo would be more meaningful to children if it had some sort of physical foundation, he advocated for including such a robot in the Logo environment.

The initial experiments with Logo had children use terminals to connect to a time-sharing system. This allowed them to control turtles, both real and virtual, as well as compose music. Toward the end of the 1970s, microcomputers began to take off. Several Logo interpreters were written for these machines, and so the virtual turtle we all know and love came to the classroom.

During the 1980s, Logo was a popular addition to elementary school classrooms. This was where I had my first experience with this language. The thing is, apart from drawing interesting geometric patterns, teachers did not make much use of Logo. I think they saw it as a means to teach about computers, but not as the original mathematical playground its creators envisioned. As the 80s drew to a close, Logo started to see less use, though the concept of turtle graphics lives on in many programming languages.

Also, and I think this is a real shame, Logo saw very little use for serious programming. I believe that one of the reasons was that since it was marketed to children, many people assumed it was a toy and therefore not worthy of serious use. Moreover, most Logo interpreters were quite slow. This is both because of Logo’s dynamic features but also because several architectural problems led to inefficiencies. (I will write about some of these inefficiencies in later posts.) For now, suffice it to say that I think this language deserves another look both for education and general use. Every now and again there have been attempts at revival, and I am under no illusion that I am likely to make Logo more popular, but I am sure that I can have fun playing with it and writing about it!

My Logo Project

I started playing with Logo again when the Agon Light microcomputer was released. I was looking to start a largeish project for this wonderful little system, and someone on Facebook suggested that I write a Logo interpreter for it. I decided to set out to refresh myself on the language as well as look at several implementations of it. In the past few months, I have amassed quite a library of Logo books and old software disks. As I have been playing with the language, I decided that I wanted to make a nice full-fledged, and fast Logo using the LCSI Logo dialects as my standard. The Logo I am looking at most closely is the Apple Logo II interpreter because I have an Apple IIc, and I found a boxed set is Apple Logo II on eBay.

My original intention was to code the interpreter in ez80 assembly specifically for the Agon Light, and so I started making a heap allocator along with a word lexer. As I explored the language more deeply, however, I decided that I wanted a Logo that could be used more generally. So I abandoned my assembly interpreter and turned to C. Thus, emLogo is born. After reviewing the output of llvm for the ez80 processor, I think that my C implementation will do just fine on the Agon, but it will also be able to be used on other hardware. Also, I want to embed Logo in some of my other educational software and so I am going to make this an embeddable library for maximum reusability.

emLogo goals and roadmap

The idea for my embeddable Logo is to provide a language core with the ability to add additional modules. This core will consist of the basic Lispy functions of Logo. After that additions can be added on a per-system basis (turtle graphics, files, text io, etc.)

The roadmap for the project is:

  1. Create a basic text mode interpreter for formal Logo in C, targeting the Linux console.
  2. Add the traditional set of language kludges to create the informal Logo.
  3. Create an SDL-based Logo environment using my embeddable Logo. This will primarily target we assembly.
  4. Create an environment for Agon Light, coding some sections in ez80 asm as needed for speed.
  5. Add my own kludges to modernize my language a bit.

Along the way, I will discuss and correct some pain points with older Logo implementations. I will also write about each piece as I create it. All of my creations will be open source, so as I write the code I will be linking to it on GitHub.

So this is going to be my hobby project for a while. I hope you will follow along so that you can learn the inner workings of my interpreter. Most of all, I hope you will try your hand at writing some Logo code. It truly is a language for learning!

Links and Further Reading

I encourage you to play with logo. Below are some links to get you started. The books are all in archive.org, so you can borrow them simply by following the links. Enjoy!

Logo Websites

  • Logothings - Cynthia Solomon’s personal history of Logo.
  • The Logo Foundation - A wealth of information about Logo.
  • JS Logo Interpeter - This is a nice implementation of Logo with turtle that runs directly in your web browser.
  • Logo Computer Systems Inc. (LCSI) - Creators of Apple Logo (and many others). They still provide logo based products for education.
  • NetLogo - A modern agent simulation system which uses a derivative of logo.

Logo Interpreters

  • UCB Logo - This is a nice modern logo interpreter, often referred to as the most complete logo implementation.
  • IBM Logo - An LCSI Logo for the IBM PC (runnable under dosbox). The logo screenshots in this article are from this interpreter.
  • Apple Logo II - Logo for the Apple II (my favorite implementation)

Logo Books

Computers   |   Home   |   Humor   |   Links

Visit me on Mastodon.