Sunday, August 27, 2023

Why Listack? A personal journey.

Why Listack?  By that, I mean, why did I go to the trouble of creating the language at all?

Easy answer - I'm a language geek.  I like languages, human and programming.  I collect programming language books, and read them for fun.

Harder answer - I'm bored.  This is something that is challenging me, and making me learn new things.  Mostly by trial and error, partly through reading books (Crafting Interpreters by Nystrom is great!) and watching videos.

I started learning Python a couple years ago to get back into programming.  I started programming when I was 12 and received a Commodore Vic-20 for Christmas.  I eventually saved up my pennies and bought a Commodore 64 on layaway.  a decade later (early 1990's), I went to college for "computer science", and was... disappointed with the education provided.  I worked for the university to make money (a bit above minimum wage), and ended up being one of the two student managers for the computer labs.  We supervised around 40 lab consultants, and reported to a full time staffer.  I dropped out of college (the second time, mind you) to join the Army (again).  I just lost interest at the beginning of my senior year.  Especially after I noticed that I was helping the grad students with their thesis projects.  Especially especially after finding out that the local programming jobs (mostly at Compuserve) paid a dollar more an hour than working at McDonalds.  So I quit, went to work for McDonalds for a year an a half, and finally got back into the Army.  (They don't like taking in retreads.  A retread is worth 1 point, where a new recruit is worth 8 to the recruiter.)

History - I bought a book on the Forth programming language from a library sale when I was a teenager for a quarter.  I've been interested in its simplicity ever since.  I read the book about the same time I got my first real calculator - an HP 11C, which I still have and use.  The old HP calculators work in Reverse Polish Notation:  instead of 2 + 3, you enter 2 3 +.  Just like Forth.  RPN = postfix notation = stack based language.

Despite its power and simplicity, Forth is what is called a "Write only" language.  It's easy to write programs in it.  It's terrible to go back to and debug later.

While I was playing around with the esoteric languages (thanks, Truttle1), I ran across False, a minimalist stack-based language.  I implemented it, and saw the power of the concept of quoted programs.  I then found Factor.  It advertised itself as  "... a concatenative, stack-based programming language with high-level features ..."  From there I found Joy, the concatenative (AKA stack based, AKA postfix) language that drew the most academic attention, because it was created (and advertised) by a full Professor who had the mathematical logic to justify it.  (Do check out his papers.  They're quite readable, which is unusual for functional languages and combinatory theory.)

The power of functional programming laid bare in its most essential, simplified, true form is astonishing.  But it's not easy to read, unless this like reading enjoy you.

And then it occurred to me:  words (functions) are just tokens in a list.  Lists can be rearranged!  All I needed was a coherent naming convention and a means to tell whether and how far to move the tokens.  Words can be rearranged, but get executed serially, first come, first served.  When Listack encounters a word, it checks to "fix", and moves the word around if necessary.  (Words are executed serially, one after the other, with no priorities other than 'first come, first served'.)  And thus, slowly, Listack is taking shape.

How is Listack different from the horde of other stack based languages? 
Universal Function Call Syntax.
The four functional word forms:

Postfix:                                          .word            after all arguments
Infix:                                               word            after first argument
Prefix:                                             word:           before all arguments
Callable:                                         word()          before parens around arguments
Immediate:                                     word             after arguments

You can use any of these with most function words.  They won't have much effect on Immediate words, of course, because Immediate and Postfix are how everything actually works.  But you can type in your program in the style you find most suitable.  They all work, with just a little effort on the programmer's part.

These are all the same program:

+: 1 2 if: {=: 3} {println: "True!"}{println: "False"}
1 + 2 = 3 if {"True" println} else {"False" println}        # else is semantic sugar
1 2 .+ 3 .= {"True".println} {"False".println} .if            # This is how it actually executes.
+(1, 2) if(=(3) then {println("True")} else {println("False")})    # then is also semantic sugar

But it could also be written as:

if: (1 + 2 = 3) then {println("True")} else {"False".println}

The point is, you, the programmer, get to decide how you want your program to look.  They all work the same, because words are just tokens in a list that are executed serially.