25 Apr 2025
Planet Lisp
Joe Marshall: Get Over It (ai content)
I'm tired of people complaining about all the parentheses in Lisp, so I told Gemini to vent for me. This came out pretty good.
I suppose I'm guilty of contributing to the glut of AI slop, but while the text and tone are generated, the core idea and sentiment is mine, so it isn't pure slop.
Alright, let's drop the hand-holding. You - yes, you - the one still whimpering about the parentheses in Lisp. It's time someone told you bluntly: Get over it.
Your constant refrain about "too many parentheses" isn't some profound insight into language design; it's a confession of intellectual laziness. It screams that you encountered something different, something that didn't conform to the aesthetic you were spoon-fed, and you threw up your hands rather than engage your brain.
Are parentheses really an insurmountable cognitive barrier? Are matching pairs of symbols truly beyond your capacity to track? Let's be honest. The core issue isn't difficulty; it's unfamiliarity coupled with a stubborn refusal to adapt. You've decided what code ought to look like, and anything else is dismissed as "hard" or "ugly" without genuine effort.
Thousands upon thousands of programmers - people with brains presumably no bigger than yours - have not only managed Lisp's syntax but have thrived with it. They've built complex, powerful systems. They didn't possess some secret anti-parenthesis superpower; they simply possessed the willingness to learn and adapt. They saw the structure, the consistency, the power behind the syntax, instead of getting stuck on the superficial shape of the characters.
Your complaint isn't about usability; it's about preference, and a remarkably shallow one at that. It's like refusing to read a brilliant novel because you don't like the font. It demonstrates a lack of curiosity, an unwillingness to look past the surface.
So, here's the unvarnished truth: The parentheses aren't the problem. Your rigid thinking is. Your demand that every language cater to your pre-existing biases is.
Stop whining. Stop making excuses based on trivial syntax. Either put in the minimal mental effort required to see the structure beneath the curves, recognise the direct representation of the abstract syntax tree, and understand why it is the way it is - or don't. But don't pretend your aesthetic preference is a legitimate technical critique.
The Lisp world isn't waiting for you to overcome your parenthesis phobia. It's moving on, building things, leveraging a unique and powerful paradigm. You can either engage your intellect and join in, or you can stay on the sidelines complaining about the punctuation.
Frankly, it's time to grow up and get over the parentheses.
25 Apr 2025 7:00am GMT
24 Apr 2025
Planet Lisp
Marco Antoniotti: Emacs Lisp Programming with DeepSeek: A New Widget
The Emacs widget
library is useful; alas its guts are ... semi-documented and most of its inner working a bit mysterious. I wanted a column widget where I could insert and remove a few "line-like" widgets. The editable-list
widget does not cut it (too many extra things: the INS and DEL buttons) and the group
widget is too inflexible.
After too much time trying to understand all the intricacies of the widget
library (see my rant in my previous blog post, which perfectly applies in this case) I asked DeepSeek to help me out. The result, the dynamic-group
widget (after several iterations and mistakes on part of DeepSeek) is below. It works satisfactorlly, although it could be improved by anybody with a better understanding of the widget
library. What is does is to manage a colimn of line-like widgets adding and removing from the end of the :children
list. Check the demo-dynamic-group
for a test run.
It has been fun. Although I still want a better widget! That's why I am posting this for anybody to pitch in. Any help is welcome.
BTW. There still are some warts in the code. Can you spot them?
;;; Code: (require 'widget) (require 'wid-edit) (define-widget 'dynamic-group 'default "A container widget that dynamically manages child widgets in a column." :format "%v" :value () :tag "Dynamic Group" :args nil ;; Core widget methods :create (lambda (widget) (let ((inhibit-read-only t)) (widget-put widget :from (point)) (dolist (child (reverse (widget-get widget :children))) (widget-create child)) (widget-put widget :to (point)))) :value-get (lambda (widget) (mapcar (lambda (child) (widget-apply child :value-get)) (widget-get widget :children))) :value-set (lambda (widget value) (widget-put widget :value value)) :value-delete (lambda (widget) (dolist (child (widget-get widget :children)) (widget-apply child :value-delete))) :validate (lambda (widget) (let ((children (widget-get widget :children))) (catch :invalid (dolist (child children) (when (widget-apply child :validate) (throw :invalid child))) nil))) ) (defun dynamic-group-add (widget type &rest args) "Add a new widget (of TYPE and ARGS to the WIDGET group." (let ((inhibit-read-only t)) (save-excursion (goto-char (widget-get widget :to)) (let ((child (apply 'widget-create (append (list type) args)))) (widget-put widget :children (cons child (widget-get widget :children))) (widget-put widget :to (point)) (widget-value-set widget (cons (widget-value child) (widget-value widget))))) (widget-setup))) (defun dynamic-group-remove (widget) "Remove the last widget from the WIDGET group." (when-let ((children (widget-get widget :children))) (let ((inhibit-read-only t) ;; (child (car children)) ) (save-excursion (goto-char (widget-get widget :from)) (delete-region (point) (widget-get widget :to)) (widget-put widget :children (cdr children)) (dolist (c (reverse (widget-get widget :children))) (widget-create c)) (widget-put widget :to (point)) (widget-value-set widget (mapcar 'widget-value (widget-get widget :children))) (widget-setup))))) (defun demo-dynamic-group () "Test the dynamic-group widget." (interactive) (switch-to-buffer "*Dynamic Group Demo*") (kill-all-local-variables) (let ((inhibit-read-only t)) (erase-buffer) (widget-insert "* Dynamic Group Demo\n\n") ;; Now I create the `dynamic-group'. (let ((group (widget-create 'dynamic-group))) (widget-insert "\n") ;; The rest are just two buttons testing the widget's behavior, ;; invoking`dynamic-group-add' and `dynamic-group-remove'. (widget-create 'push-button :notify (lambda (&rest _) (dynamic-group-add group 'string :format "Text: %v\n" :value (format "Item %d" (1+ (length (widget-get group :children)))))) "(+) Add Field (Click Anywhere)") (widget-insert " ") (widget-create 'push-button :notify (lambda (&rest _) (dynamic-group-remove group)) "(-) Remove Last") (widget-insert "\n")) ;; Wrap everything up using the `widget-keymap' and `widget-setup' ;; functions. (use-local-map widget-keymap) (widget-setup))) (provide 'emc-dynamic-group)
'(cheers)
24 Apr 2025 8:52pm GMT
Joe Marshall: Lisp Debugger Wins
I'm gathering statistics from thousands of pull requests in GitHub. I wrote a little Lisp program to do that. It's taking a long time because it has to make a lot of API calls to GitHub and the calls are rate limited.
After about half an hour, I got an unexpected error. A user who made the pull request I was looking at had deleted their account. No problem. I used the Lisp debugger to walk up the stack to a convenient frame and returned NIL from that frame, causing that particular PR to be skipped. The program continued running from where it left off. I didn't have to restart from the beginning and lose a half hour of work.
The Lisp debugger for the win!
24 Apr 2025 6:00pm GMT