Paolo Amoroso's Journal

interlisp

Planet Python carried out my request to remove my blog from the aggregator. Now their feed no longer syndicates my posts about Python, which I'll no longer write much about.

Planet Python is an aggregator of blogs, podcasts, and other resources of interest to the Python community. In late 2019 I submitted the feed of Python posts of my old blog, later updating it to point to my new blog.

I was learning the language and sharing on the blog my experience with coding projects and other experiences. But although I had great fun with Python and accomplished a lot I'm proud of, my interest waned as I rediscovered my old love Lisp.

I encountered Scheme in the early 1990s at an introductory computer science class based on Structure and Interpretation of Computer Programs, fell in love with the Lisp family of languages, and learned Common Lisp and Emacs Lisp. Lisp became my only language until the early 2010s when real life claimed my time and attention. Near the end of the decade, intrigued by Python and its massive ecosystem, I decided to learn it.

At the beginning of 2023 I discovered Medley Interlisp and got hooked.

Using Interlisp and its environment made me realize Lisp is the language that comes most natural to me, I'm most productive with, and gives me joy and not just fun. I never mastered and enjoyed other languages to the level of Lisp. And my projects turned out not to need Python's batteries.

I'll still maintain a reading knowledge of Python and keep up with its ecosystem. But this journey made me readjust my focus on Lisp, now my only language.

It's good to be back home.

#Interlisp #Python #Lisp #blogging

Discuss... Email | Reply @amoroso@fosstodon.org

I integrated Femtounit with the File Manager by defining the new type TESTS for Femtounit tests and redefining DEFTEST in terms of it.

It turns out it's not a good idea as the tests get duplicated. The DEFTEST macro expands into a DEFINEQ function definition and the File Manager notices both, the DEFTEST form of type TESTS and the function of type FNS.

The fix seemed simple, assigning tests to an existing type such as FNS. First I removed TESTS with (DELDEF 'TESTS 'DEFINE-TYPES), then replaced the type argument TESTS with FNS in the XCL:DEFDEFINER form. But when I tried to edit a sample test TEST.PLUS for the PLUS function with (ED 'TEST.PLUS :DONTWAIT), SEdit quit with the error:

Warning: Couldn't find a hash-table for FNS definitions.
One will be created.
Could not find fns definition for TEST.PLUS.
Could not find fns definition for
TEST.PLUS

Back to the drawing board.

#femtounit #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I integrated Femtounit, my Interlisp unit test framework, with the File Manager and the SEdit structure editor.

To achieve this I defined the new File Manager type TESTS for Femtounit tests and redefined DEFTEST in terms of it, then tweaked the code formatting of tests in SEdit. Now the system notices and keeps track of new and modified tests.

Here's the File Manager type menu, which SEdit pops up when opening a test, with the DEFTEST option highlighted under TESTS:

Interlisp File Manager menu with the Femtounit types.

Also, now SEdit handles and properly formats test definitions like this of a function SQUARE to compute the square of its argument:

SEdit editing a Femtounit unit test definition on Interlisp.

Implementing the new features was much easier than expected.

The traditional way of adding types to the File Manager, described in the Interlisp Reference Manual, involves writing a dozen functions for most of which it's not clear how they're supposed to work. Medley 1.0 added support for two easy to use File Manager type defining forms that replace all that, XCL:DEF-DEFINE-TYPE and XCL:DEFDEFINER. This code is all it took for Femtounit's new TESTS type:

(XCL:DEF-DEFINE-TYPE TESTS "Femtounit unit tests")

(XCL:DEFDEFINER (DEFTEST (:PROTOTYPE
                            (LAMBDA (NAME)
                              (AND (LITATOM NAME)
                                   `(DEFTEST ,NAME ("Arg List")
                                      "Body")))))
                TESTS
                (NAME PARAMETERS &BODY BODY)
   `(DEFINEQ (,NAME ,PARAMETERS
      (LET ((FTU.TEST.NAME (APPEND FTU.TEST.NAME (LIST ',NAME]
        ,@BODY))))

This additional tweak makes SEdit format and indent DEFTEST unit test definitions the same way as DEFUN function definitions in Common Lisp:

(SEDIT:DEF-LIST-FORMAT DEFTEST CL:DEFUN)

The simplified process is not discussed in the Interlisp Reference Manual, where I'd have expected, but in a more obscure source, the Medley 1.0 release notes from page 52 of the PDF document. My proactive reading of all the documentation paid off as it let me spot such crucial information and save a lot of work.

#femtounit #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I'm writing another Interlisp program, Sysrama, an Interlisp documentation tool for presenting information on the Lisp objects of a program. It produces reports that list the types and signatures of functions, the fields of records, global variables, property lists, Executive commands, and more.

The way I reference the details of Lisp objects when coding gave me the idea for Sysrama.

I often forget the names and signatures of the functions or the names of the record fields I need. Browsing or looking up the code for referencing them is a source of friction.

Interlisp comes with the powerful program analysys tool Masterscope that gives its best with answering specific questions on the internals of programs. But it has a steep learning curve and it doesn't provide the kind of big picture view I seek. Instead, I wanted a simple tool for producing an overview of the main Lisp objects in a program.

This is a sample report Sysrama prints on another of my Interlisp programs, Stringscope:

Sample output of the Sysrama documentation tool for Interlisp.

The main sections group objects under the same File Manager types, such as FNS or RECORDS. This is because Sysrama can extract information only from programs under File Manager control.

Suppose you want to analyze the Lisp program MYPROG. Once Sysrama is in memory, load MYPROG:

(LOAD 'MYPROG)

To have Sysrama print a report with information on MYPROG evaluate:

(SUMMARIZE 'MYPROG)

You can narrow down the information to specific File Manager types such as FNS and RECORDS:

(SUMMARIZE 'MYPROG '(FNS RECORDS))

or to specific objects like the function MYFUN:

(SUMMARIZE 'MYPROG 'FNS 'MYFUN)

More documentation is available at the project repo.

Sysrama already does most of what I had in mind but I'll implement a few more features.

I'll tweak the reports to show more information on some Lisp objects. And I'll add the ability to redirect the output to a scrollable window rather than to the primary output stream. By default Interlisp windows don't save the output history and can't be scrolled back, so such a feature will help review reports that don't fit in a window.

#sysrama #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

Medley is a rich development environment but it's missing a test framework. Or so I thought. To fill the supposed gap I wrote Femtounit, a tiny — hence femto — unit test framework for Interlisp.

I wanted a small framework simple to port to or write for Interlisp, yet useful in practice. At less than a couple dozen lines of code, Femtounit took very little effort to design and write as it's based on the PCL test framework Peter Seibel described in Chapter 9 of his book Practical Common Lisp.

I reused much of Peter's design and code, adapting it to Interlisp and tweaking the reporting of tests. Femtounit outputs a single period character for every passed test, unlike the full report his framework prints.

Using Femtounit looks like this:

Usage of the Femtounit unit test framework for Interlisp.

Suppose you want to test this function that returns the square of its argument:

(DEFINEQ (SQUARE (X) (TIMES X X)))

You may define a TEST.SQUARE test function like this:

(DEFTEST TEST.SQUARE ()
  (CHECK.EXPECT (EQP (SQUARE 1) 1)
                (EQP (SQUARE 2) 4)
                (EQP (SQUARE 3) 9)
                (EQP (SQUARE 4) 16)))

To run the tests, just call the function:

(TEST.SQUARE)

which will print a period character for every passed test:

....

Some documentation is at the project repo.

After I finished the initial code of Femtounit, Larry Masinter pointed out Medley does have a test framework, and quite an advanced one. This system, which the Medley documentation simply calls test system and is much more than a framework, was originally designed to test Interlisp and its environment. The code is now in one of the Medley repos.

I thought I explored every nook and cranny of Medley and its documentation, yet I missed the test system. The system is interesting in itself and I'll use it for most of my code.

But Femtounit is a fun little learning project I still want to proceed with. It'll teach me how to integrate the framework with Interlisp for editing unit test definitions with the SEdit structure editor, as well as saving the definitions to files and managing them with the make-like File Manager tool.

#femtounit #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I'm back to work on Braincons, a Brainfuck implementation I'm developing with Medley Interlisp.

The new code I wrote implements the virtual machine (VM) and executes the Braunfuck instructions. Now Braincons can create and reset a VM, load a program into it, and execute the program until completion or for a designated number of steps.

The Lisp record BRC.VM represents the VM and holds the Brainfuck program, memory, machine state such as the instruction and memory pointers, and virtual I/O devices. All the functions that operate on the VM accept a BRC.VM record as an argument, update it as necessary, and return the record.

To decouple as much as possible I/O from other subsystems, BRC.VM contains the IN and OUT fields to hold a Lisp input stream and a Lisp output stream.

Any functions that need to read data or display output on behalf of the VM can do I/O to the relevant VM streams. This adds flexibility as most Interlisp text and window output functions accept streams as arguments.

Having the book A Philosophy of Software Design fresh in my mind after recently reading it, to design the Braincons VM I deliberately sat down to think about and write a specification of how the features needed to work. Although the book presents a lot of material I haven't absorbed yet, this preliminary work helped me design a relatively small and clean VM interface and saved some code rewriting.

Now that Braincons can parse, compile, and execute Braunfuck programs, the next step will be to build the user interface for editing and running programs, as well as inspecting the VM and its state.

#braincons #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I finished implementing the commands of Stringscope, the string listing tool I'm developing with Medley Interlisp.

After Sort, Reset, and Exit I wrote the code for Min Len, Find, and Get. I also added the new command Info to show in the prompt area some statistics about the strings. Coding the other commands gave me the idea and Implementing Info seemed easy, so I did it.

Now Stringscope looks like this, with the prompt area attached to the top side of the main window and the menu at the right side:

Window of the Interlisp program Stringscope with an advanced version of the command menu.

I renamed the menu item Set threshold to Min Len as the former was too wide and stood out. Min Len is more consistent with the documentation and code of Stringscope. In addition, I centered the items instead of aligning them flush left. This is the more idiomatic way most traditional Interlisp programs and system tools lay out menus.

To explain how the commands work I recorded a screencast that walks through the features and input validation of Stringscope.

I demonstrated the program by opening and interacting with two binary files, the DOCTEST.TEDIT document created with the TEdit rich text editor and the program's compiled executable STRINGSCOPE.LCOM. I also threw in some invalid data as input to show input validation in action.

After writing the code of the commands I realized Stringscope grew to support all the features I initially planned, plus a couple more I thought of along the way.

Medley Interlisp seemed overwhelming and intimidating at first but it was too much fun, so I pressed on using and studying the system. The effort paid off and now I can not only find my way around, but also create a small yet complete program with a GUI. This is a milestone to celebrate.

It's probably time to ship version 1.0 and start thinking of how to improve Stringscope and its design.

#stringscope #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I'm having a lot of fun working on the commands of Stringscope, the string listing tool I'm developing with Medley Interlisp.

I implemented the Sort menu item with its subitems Ascending and Descending, as well as the Reset item. I added also the Exit item for quitting the program, a low-hanging fruit that just required calling the CLOSEW window manager function for closing the main window.

The main window of Stringscope, the command menu, and the prompt area now look like this:

Window of the Interlisp program Stringscope with an early version of the command menu.

The commands didn't require too much new code. I take it as a sign the foundation is solid, or at least not too shaky. And Interlisp's powerful menu system made things easier. But there's some code duplication I'm not satisfied with that will need refactoring.

The next commands to implement are the ones that take input from and output to the prompt area: Get, Find, and Set threshold.

#stringscope #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I'm enhancing Stringscope with a permanent command menu and a prompt area. The menu, an item of which holds a submenu, attaches to the right side of the main window, the prompt area to the top of the main window above the title bar. This is what the main window looks like now:

Window of the Interlisp program Stringscope with an early version of the command menu.

This way of arranging menus and secondary windows by attaching them to a main window is typical of Interlisp programs with a GUI. The system supports this design with functions like the ones I used, CREATEMENUEDWINDOW to create and attach a menu and GETPROMPTWINDOW for doing the same with a prompt window.

The menu comprises these initial items and subitems:

  • Get: reads the strings of a new file
  • Find: searches for strings matching a specific text
  • Sort: sorts the strings in the following order
    • Ascending
    • Descending
  • Set threshold: changes the minimum length of strings
  • Reset: redisplays the strings read from the current file

The prompt window is an area for displaying status messages and receiving user input such as the name of a new file to read.

So far the Stringscope code sets up the menu and the prompt window. The menu handling function, however, is just a stub that prints to the main prompt window the selected menu item.

The next step will be to implement the commands the menu calls.

#stringscope #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I moved the Stringscope project infrastructure from a GitHub gist to a full repo. The gist is now unmaintained and links to the repo.

Announcing my new Interlisp project Braincons I motivated setting up its infrastructure as a repo with a number of reasons boiling down to convenience. Code is still readble despite the formatting Interlisp encodes, source files no longer need conversion, and a full repo is more flexible. I moved Stringscope to a repo for the same reasons.

#stringscope #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org