Newest posts:
The Genius of Lisp
I have just read the book The Genius of Lisp by Cees de Groot. It was a very interesting read. The book tells the history of the Lisp programming language from 1958 to today and also how Lisp, as one of the earliest high level programming languages, has influenced other programming languages over the years. It also goes into the technical details of how Lisp dialects were implemented and the differences between them. And it explains the mathematical groundwork by Alonso Church and Alan Turing for the Lambda calculus, and how John McCarthy used it to build his language.
The technical details are well explained and as easy to follow as they possibly might be. There is example code in IBM 704 Assembly with explanations, practical implementation examples in JavaScript that is easy for present-day programmers to follow, explanations in pseudocode and of course lots of code examples in various Lisp dialects. The early chapters on the mathematical underpinnings of lambda calculus and the foundational work for Lisp and its practical implementation gave me a proper understanding of it even if my mathematical knowledge is very limited.
For me personally, I felt that after reading the book, I now have a better understanding of the different dialects of Lisp, who created them and for what purpose. I knew about some of the dialects and some of their traits, but I learned a lot more about them. For instance, I did not know that Common Lisp is a thoroughly object oriented language and this surprised me.
Although I knew about the previous AI hype with "expert systems" and the AI winter that coincided with the economic downturn in the late 1980s, the book enlightened me with more details and more about its consequences for the AI language Lisp. We are fast heading into a new AI winter now since the LLM providers have unsustainable business models, but I think the consequences for Python will be less dire since its growth in popularity started long before the present LLM craze and it is less closely tied to AI research than Lisp was. (I bet on Python when I studied at the only Norwegian University or College that taught it instead of Java as their first language and since then, its popularity has only grown, from at that time being less used than Java and C#, but now being the second most used language after JavaScript/TypeScript according to Stack Overflow Survey.)
Reading The Genius of Lisp has strengthened my belief in Lisp as a brilliant programming language worth exploring further. It is not on the top 20 list of programming languages now, but it is powerful and elegant with its homoiconic s-expressions for both code and data. Learning more about the different dialects through the book also further convinced me of my previously somewhat uninformed hunch that Clojure and Scheme are Lisps I should look into further. (I am already a Guix user thanks to David Wilson's brilliant SystemCrafter videos, but I haven't had the time to delve deeper into Scheme.) My first meeting with Lisp was in Emacs, and I will continue to play with Emacs Lisp as well.
All in all, it was a good read and I highly recommend this book to people interested in programming, computer history and the mathematical underpinnings of functional programming, the Lambda calculus. Some previous knowledge of JavaScript is useful for understanding the implementation of Lisp functions in the early chapters.
Dunk Dunk
Ro! 🇳🇴
Speed improvement hack for dired with EWW
I have used EWW in Emacs for some of my browsing for a while and it does the job very well unless browsing single page applications or other sites that do not send HTML unless you run JavaScript. Thank you Lars Magne Ingebrigtsen for making EWW! Hitting R filters out all the noise for a really pleasant reading experience. It is good to browse within Emacs with no context switching in a keyboard-driven way.
(Apropos the joys of context switching: When I am a bit tired, I use Emacs keybindings everywhere. Tap-to-click is naturally off on my laptops to prevent insanity. I am often able to "help" my students a lot within just a few seconds of random keybindings and clicking everywhere on their laptops. It is really good for students to learn patience and tolerance towards people unable to handle computers. They need that for their user support class and future work in the IT industry.)
When Joshua Blaise wrote about his eww setup and use, I read it with interest and stole most of his ideas for my own config. The important one for this little hack is that I set up URLs with endings like .mp3, .mp4, .m4v, .mkv etc to launch in mpv when browsing to them. This makes watching videos and listening to audio content easy with EWW. EWW is also good for browsing local files by hitting W with point on a file in dired.
In dired, I usually launch external programs for photo editing, media playback etc by pressing & with point on a file name. This brings up the completing-read interface in the minibuffer which asks me if I would like to use dired's guess as to which program to use (which I have set to guess xdg-open first) or something else. I press return and then mpv, gimp, darktable or whatever launches with the file.
I had an html file in my downloads folder which I launched with W to read in EWW. I then, by mistake, hit W when on a .mp3 file, and it launched in mpv. Since W launches the file in EWW and EWW was configured to open .mp3 files in mpv, it did that without asking me which program to use. It is faster to hit W than to hit & RET, or in worst case write a program name and RET. So now I launch media files with W in dired in stead of using &. It speeds things up a bit.
(While writing this, I also remembered that I have functions for playing enclosure links and links in elfeed through mpv that I might replace or improve by shuffling the links to EWW or einar-browse-url-mpv. I wrote my configuration for elfeed very early in my Emacs journey, without really understanding any of it, by copying snippets from the Emacs wiki, blogs and Reddit so it is high time to look at it again anyway. I can probably simplify it.)
Here are the relevant parts of my configuration for EWW to get this working:
(defun einar-browse-url-mpv (url &rest _args) "Opens URL in mpv." (start-process "mpv" nil "mpv" url)) (use-package eww :config (setopt browse-url-handlers '(("\\(youtube\\.com\\|youtu\\.be\\|vimeo\\.com\\|twitch\\.tv\\)" . einar-browse-url-mpv) ("\\.mp3$" . einar-browse-url-mpv) ("\\.mp4$" . einar-browse-url-mpv) ("\\.webp$" . einar-browse-url-mpv) ("\\.m4v$" . einar-browse-url-mpv) ("\\.mkv$" . einar-browse-url-mpv) ("\\.pdf$" . einar-browse-url-pdf) ("." . eww-browse-url))))
Fix Emacs python-mode REPL and org code block with python evaluation problems
For a while now, the python shell in Python mode in Emacs has not worked properly on my work laptop. I get some strange glyphs in the top of the python shell buffer when opening it from a file with C-c C-p and when I tried importing a file with C-c C-c, I would get an error saying stringp was nil and every character in what I tried to import was written first once, then together with the next, then the next three and so on. It looked somewhat psychedelic and was more or less unusable.
I also had trouble evaluating python code blocks in org mode which has been annoying when presenting with inter-present-mode for my students or exporting from org files I used for presentations to PDF or docx to upload to our school's learning platform (it's learning). In org, I would get the same error saying stringp was nil when evaluating code blocks that I would get when trying to import files to the REPL in python mode.
I first thought the problem was related to my einar-python-virtualenv function which locally changes the python-shell-interpreter for a file if it is in a project with a virtual environment since I made that quite recently, but the strange thing was that it worked perfectly on GNU Guix on my main machine at home. I then thought maybe it was a Windows 11 problem since I only experienced it at work, so I tried on a Raspberry Pi 4 at work with the latest Raspberry Pi OS and I had the same problem.
I then tried launching Emacs with -q to see if the problem was related to my config or not. When I then launched the python shell from a file with C-c C-p, the REPL itself worked slightly better, but I still got some strange glyphs at the top. I then spent some time trying to figure out where in my config the problem appeared and removed first the einar-python-virtualenv and then my configuration for python-mode, but the problem persisted. I also looked into whether some setting for comint-mode might cause the problem.
After spending one and a half hour trying to troubleshoot this on Monday, I today realised I updated Python to 3.14 on my work Windows 11 laptop a while ago. I checked the python version on the Raspberry Pi and it was 3.13. I checked packages.guix.gnu.org and Guix uses version 3.11. I thought maybe something changed in one of the newer versions. I had a look at news for version 3.14 and did not find anything promising. I then checked out what was new in 3.13 and one of the first things was a new and improved python shell.
Luckily, you can get the old shell that python mode in Emacs works with by setting the environment variable PYTHON_BASIC_REPL to something. When I added this function call to my Emacs config for python mode, the python REPL works in python mode again and it is possible to evaluate org code blocks and export files that will evaluate them on export again:
(setenv "PYTHON_BASIC_REPL" "1")
I write this so others experiencing the same problem can find a solution. In the long term, python-mode, python-ts-mode and org mode needs to work with the new and improved python shell since the old shell will probably be removed at some point in the future, but for now, just setting the environment variable is enough to get both the REPL and org code blocks working again.
Use python shell from virtual environment if there is one in Emacs
About a week ago, I made a function to use python from a virtual environment if there existed a directory called venv within the project the file is inside. This works for me since I tend to call virtual environment directories venv. The point of the function is to get access to the packages within that virtual environment when using the python shell to evaluate code from a file or interact with its functions, classes and variables through the REPL. I usually write my code and then test it through the REPL and do the necessary adjustments when there are mistakes. (I probably do this since I learned basic programming principles by teaching myself HyperTalk by reading the Help stack and experimenting in the Message Box (a REPL) in HyperCard in the late 80s.) I think a lot of people overlook this great way of working in interpreted languages.
Today, I had a look at that function again. I thought it would be really nice if I could find the python executable within a virtual environment no matter what the virtual environment directory is called. I found that this would work:
(defun einar-python-virtualenv () "Sets the python shell to python from a virtual environment if one exists." (when (project-current) (let ((pythonpath (nth 0 (directory-files-recursively (nth 2 (project-current)) (if (eq system-type 'gnu/linux) "python$" "python.exe$"))))) (when (file-exists-p pythonpath) (setq-local python-shell-interpreter pythonpath)))))
I need to run this function whenever I open a python file to set the correct path to the python shell for that file. This is done by adding the function to the python-mode hook like this since the mode hook is run every time you open a python file:
(add-hook 'python-mode-hook 'einar-python-virtualenv))
With this in place, whenever I open a python shell with C-c C-p from a python file, I get a python shell from within the virtual environment of that file's project, or I get the system python if there isn't a virtual environment within the project the file is part of.