Programming Language Study–Lisp (2)

Today I want to learn some Lisp, and I will be reading from Practical Common Lisp by Peter Seibel. As usual, I will write in a stream-of-consciousness style while I learn.

My previous post was about Python, and of course I am going to continue learning Python, but this series is not just about one language. I am going to look at whatever programming languages suit my interests. Once you know enough of a language to get a job, then you can flit around and learn whatever you want to learn. So in parallel with Python, I will also study Lisp.

Lisp is another language I have been meaning to learn forever. I don’t remember exactly how I first discovered it, but I do know that Peter Norvig specifically mentions Lisp in his very famous essay, “Teach Yourself Programming in Ten Years”. Also, it’s a very strange-looking language. It’s difficult to even get started using the LISP console. So that is what I’m going to do today.

Funny aside: several years ago I applied for a developer job with a company called Epic. They sell software to hospitals. During the phone interview, I spoke with a developer, and he mentioned using Lisp for some project, and I thought that was really cool. People would not go to Lisp for routine work. It must be something interesting and exotic for Lisp to be worth its high cost of entry.

When I went to Epic for the on-site interview and spoke with developers there, nobody had any idea what I was talking about. There was no Lisp to be found. Instead, there were using Visual Basic. I was deeply disappointed, and I got the hell out of there.

Lisp is not exactly a popular language. A company would have some difficulty finding a Lisp developer to fill an opening. So, you should not learn Lisp expecting it to win you a programming job. Learn Lisp if you are interested in programming languages for the sake of learning—and you already have a job. And who knows? Maybe one day you will use it on a job.

I’ve just been reading the first chapter of the Practical Common Lisp. So far what really speaks to me about Lisp as described in this chapter is the extensibility of the language. The author claims that a programmer can add new language features at will without having to change the core of the language or its compilers. That sounds very powerful. Java certainly does not offer anything like that. Java is what I use every day for work, but it is a tediously rigid language.

The first thing I will need to do to get started is install Lisp on my computer. I’m working on a Lenovo computer running Windows 10. It definitely did not come with a Lisp interpreter pre-installed. The book includes a chapter on setting Lisp up on your computer, but I’m sure you can Google that also.

I am going to begin here: https://common-lisp.net/project/lispbox/. This Lispbox web site offers a packaged Lisp IDE for Windows, Mac, and Linux. It was surprisingly easy to make this work. Note where it says no installation is required. All you have to do is unpack it and then you can start it right away. In Windows, all you have to do is run (double-click) the lispbox.bat file.

That said, upon running Lispbox I am presented with some kind of command line.

Tyranny of the command line

Like anybody else learning a language for the first time, I have no idea what to do with that. I recall that the Python console will act as a calculator if you can’t think of anything else to do with it, so I try entering 5 + 9. The program returns 9. Then I try 5+6 and it drops me into some crazy error menu.

What hath God wrought?

After this, I reached into my memory and found that I recalled a little about how Lisp code looks. It uses that weird list notation where the operator always comes first and the arguments are listed after it, and you put parentheses around it, like so: (+ 4 5). When I enter that on the command line, it returns 9, the sum. Now we are getting somewhere. Whether it is somewhere good is debatable.

The book I’m reading suggests viewing the Emacs tutorial here, which you can access by pressing control+h, then t. I already think I’m going to hate Emacs if you have to learn a thousand complicated keyboard sequences to operate it.

The Emacs tutorial even advises using control+[char] commands to emulate the arrow keys instead of just using the arrow keys because it’s “more efficient”. I foresee a future post where I figure out how to ditch Emacs in favor of something I don’t hate. For now I’ll stick with it while I get my bearings with Lisp. At the moment frankly I don’t know how the different parts of this IDE fit together, so it’ll take a minute to figure out how to replace one of the components with something else.

If you are following along with me, it’s probably a good idea to at least skim over the Emacs tutorial, but mastering Emacs is not my goal here, so I’m going to get back to focusing on Lisp as soon as I figure out how to exit the tutorial.

I found a way to get back to the Lisp REPL, but it looks like all I did was switch buffers. The tutorial is still open.

Let’s go back to the example from above. I typed (+ 4 5) and this returned 9, the sum. I would not be surprised if you have never seen this kind of notation before. I was first exposed to it in a class I took on algorithms and data structures. It’s not specifically just a Lisp thing. This is called Polish notation. The idea here is that the function always precedes its arguments—including even functions like + that are usually written as infix operators. One advantage of this is that it totally negates any need for an “order of operations. The notation 3 + 6 * 2 would be ambiguous if we had not all learned that multiplication has a higher precedence than addition. However, + 3 * 6 2 is unambiguous. If you attempt to compute the sum first, then you have to compute the product just to know what the second argument of the sum is. There is no other way to interpret it but (+ 3 (* 6 2)) = 15. I’m not sure why this is so yet, but Lisp seems to require both of those pairs of parenthesis. I tried evaluating (+ 3 * 6 2) and it returned 21. I don’t know what it did there, but the expected value is 15.

Now I am continuing to read from Practical Common Lisp, Chapter 2. The author tells us that anything in parenthesis like the (+ 4 6) expression is a “list”. This example is a list of three elements. The first one is a (built-in) function, and the next two elements are the two arguments we want to enter into that function. From this we can surmise that for any function f we might evaluate that function with whatever arguments we like by writing (f arg_1 arg_2 .. arg_n) where the function f takes n arguments.

As another example, the author shows us the format function, which allows you to build a formatted string and print it to a given output. Thus (format t "hello, world") tells Lisp to evaluate format with two arguments, t and "hello, world". The first argument, t, tells it to print to standard output—so it will appear on the console. The second argument is the string to be printed. This causes “hello, world” to be printed to the console.

Also, I tried it with FORMAT too and that worked, so I guess Lisp is not case-sensitive.

So far I don’t know how to define functions. Let’s read on. It looks like to define a function in Lisp we apply a built-in function called defun. The author defines a hello-world function to package the expression above and print “hello, world” to the console, like this: (defun hello-world () (format t "hello, world")). Here’s how I interpret that. It works exactly like evaluating a function. The function to be evaluated is the first element of the list. In this case it is defun. The first argument going into defun is the name of the program. The second argument is a list of the arguments required by our new function. The third argument is a list that defines the operation of our new function. Note that Lisp seems to use a space as the delimiter of items in the lists.

To evaluate that user-defined function, one would execute (hello-world). That is a list with just one element, the function, because this function takes no arguments.

I’m going to try to extrapolate this and define my own function that will take some arguments. Let’s try (defun add-two (x y) (+ x y)). I checked this to be sure: the + function will accept a variable number of arguments: for example (+ 2 3 4) is valid and evaluates correctly. My new function will accept only two arguments. This may not be the most useful function, but right now I just want to see if I guessed right about how to define a function with arguments.

I ran the defun line above to define the function, and then I executed (add-two 4 5) and this evaluates to 9 as expected. Excellent. Now we know how to define our own functions in Lisp.

There’s something really, really special about what we just did to define a function—quite a lot different from any other programming language I have used. In other languages I have used, to define a function you use a special language syntax. In JavaScript for example you might write something like function myFunction() {}. That syntax is what tells the interpreter that you are defining a function. In Lisp, defining a function uses exactly the same syntax as evaluating a function.

I’m having some difficulty thinking of how to explain the significance of this, but here’s one example to illustrate. Since functions are defined in Lisp just by evaluating the defun function, I could define my own custom function for defining functions. Since defun is a function like any other function, it can be composed with other functions. It can be used inside the definition of another function. For example, I might want to define my own custom function for defining a function that defines the function and also registers the name of that function inside a list somewhere.

Let’s say I have already defined a function REGISTER that accepts a string argument and adds the function name to the list. Also, I had to look up a function that evaluates more than one expression and I found PROGN. Thus, if you execute (PROGN f1 f2, f3 ...) then PROGN will execute f1, f2, … in sequence and return the value of the last executed expression.

Using these tools, I should be able to define my custom defun like so: (defun custom-defun (name args definition) ( (progn (register name) (defun name args definition). However, this does not work as-is. I get the following error message: “value ARGS is not of the expected type LIST.” This tells me I will have to do something special to indicate that the ARGS argument is a list type—basically some kind of typing in Lisp, but I don’t know how to specify variable types in Lisp yet.

The book we are reading will probably get around to teaching us how to do that, but I decided to Google around and see if I could find an answer immediately.

I made several attempts based on things I found on Google. All were unsuccessful. Also, I really, really hate this interface. A moment ago, I literally killed the IDE from the Windows task menu because pressing “enter” just kept feeding new lines instead of executing the command and I had no idea what it wanted from me. It looked exactly like the ordinary command line, but it wouldn’t execute anything. So before this is over I really have to find a Lisp IDE that is not horrifyingly anti-intuitive and annoying.

I have Googled around, but I still cannot figure out how to define a function that accepts a list as an argument and passes that list into another function. Everything I find on Google has functions accepting a list and then iterating over the list to perform some action with each individual element—which is not what I want to do.

This is what study is really like, even for experienced, employed software developers. That’s kinda the point of my tutorial blog posts. I want code newbies to know that we are all newbies at something—and for them to see the actual process whereby I try to learn new things.

Right now, I have decided to set aside trying to define some custom-defun type function. I think this probably can be done in Lisp, but I am still missing some of the bare minimal basics of the language. And right now I’ve just had enough of Emacs to last me for a week. So I’ll call it a day on Lisp and pick this up again in a future post. I do think Lisp will prove interesting and fun in the long run, but we have to learn the basics and make it our own. Programmers are control freaks. We rarely just accept things as given. Next post is probably when we figure out how to ditch Emacs and see if there is any alternative to SLIME for interactive Lisp. Should be fun.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s