this doesn't look bad at all! considerably better than common lisp, in particular. but i think the flatter structure of the python improves readability, and the independence of the different clauses facilitates interactive incremental testing:
>>> word = 'the'
>>> letters = 'abcdefghijklmnopqrstuvwxyz'
>>> splits = [(word[:i], word[i:]) for i in range(len(word) + 1)]
>>> splits
[('', 'the'), ('t', 'he'), ('th', 'e'), ('the', '')]
>>> deletes = [L + R[1:] for L, R in splits if R]
>>> deletes
['he', 'te', 'th']
but lisps are generally pretty good at that kind of thing, so i imagine you could formulate it slightly differently in txr lisp to support that kind of thing (i just don't know txr lisp)
as a semantic question, is this materializing the whole list (as the python does) or are the `add` calls inserting into the hash table as the loops run, thus eliminating duplicates?
I had a bug somewhere, so I selectively off some of the add expressions. They can be commented out with #; or by flipping add to list or identity to throw away the value.
The add is something which pairs with build. Lisp doesn't have "bag-like" lists. For those times when they are helpful, we can have procedural list building syntax. The build macro creates an environment in which a number of operators like add that build up or otherwise operate on an implicit list. When the build form terminates, it returns the list. (Its sister buildn returns the last form like progn).
In this function, I could just have used (push expr stack) because we don't care about the order; there would be no nreverse. That would be a better idea, actually.
We could also add the strings to a table directly, like (set [h (join ...)] t).
The hash table is built by the hash-list call. It associates the elements of the list with themselves, so if "a" occurs in the list, the key "a" is associated with value "a".
thanks! it sounds like a pretty effective system, although the form of incremental development you're describing is editing and rebuilding the program, more like c than the kind of repl flow i was talking about
the use of [] for indexing rather than clojure's list building (or as conventional superparentheses) is appealing
In TXR, we can easily recall the entire function definition at the REPL, and resubmit it, without requiring any external IDE.
Furthermore, if you have the kind of workflow where you have individual REPL commands produce results that are used by subsequent commands, the TXR Lisp listener has good support for that. When you recall an input line from history, you can use Ctrl-X Enter to execute it rather than just Enter. When you use Ctrl-X Enter, it will keep the history position and move to the next line in history rather than return to the current context. So using Ctrl-X Enter multiple times, you can resubmit a sequence of historic lines in order.
you might want to switch to the standard gnu readline keybinding for 'submit the current input line for execution and recall the next line in history', which is control-o. aside from the synergistic effect of being able to use the same keybinding in txr, bash, python, etc., it's a command which you frequently want to use several times in a row, and binding such a command to a sequence of two keystrokes makes it disproportionately more clumsy. you may have noticed recent versions of emacs permit you to run a keyboard macro repeatedly with c-x e e e, and it's a huge usability improvement
I see in the readline sources that it was added in 2021. (The git history of Chet Ramey's repositories is horrible; he just adds big patch bombs with no individual commits.)
I independently conceived the feature in 2015. I had not seen it anywhere before that, nor have I seen it since!
commit 51322f6c66d153d2f008a227c5e517f6fb34dbab
Author: Kaz Kylheku <kaz@kylheku.com>
Date: Thu Dec 31 05:30:46 2015 -0800
linenoise: submit and stay in history.
I see the readline source code gives credit to copying this feature from the Korn shell. In misc.c there is a comment:
/* The equivalent of the Korn shell C-o operate-and-get-next-history-line
editing command. */
(Where would Bash imagination be without Korn.)
I see in the ksh93 sources that this appeared in or before 2012. (Again, patch bomb wall.)
What buildn will do with the list is simply lose it. The last form can extract it and do do something with it.
When you might use it is when the goal isn't to build a list which escapes. The construct supports queuing semantics (insert at one end, take from the other), so you can use buildn to express a breadth-first traversal that doesn't return anything, or returns something other than the list:
(defun bf-map (tree visit-fn)
(buildn
(add tree)
(whilet ((item (del))) ;; (del) from front
(if (atom item)
[visit-fn item]
(each ((el item))
(add el)))))) ;; (add) to back