3 ms·
TXR Lisp: (defun edits1 (word) (hash-list (build (each ((i 0..(len word)) (j 1)) (let ((le [word 0..i]) (rj [word j..
by kazinator 2y ago
TXR Lisp:
(defun edits1 (word)
(hash-list (build
(each ((i 0..(len word)) (j 1))
(let ((le [word 0..i]) (rj [word j..:]) (ri [word i..:]))
(add (join le rj)) ;; deletes
(each ((c "a".."z"))
(add (join le c rj)) ;; replacements
(add (join le c [word i] rj))) ;; prefixes + inserts
(or (empty le) (empty ri) ;; transposes
(add (join [le 0..-1] [ri 0] [le -1] [ri 1..:])))))
(each ((c "a".."z"))
(add (join word c)))))) ;; suffixes
- kragen 2y agothis 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?
- kazinator 2y agoI 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".
- kragen 2y agothanks! 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 what does buildn do with the built list?
- kazinator 2y agoWhat 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
- kazinator 2y agoIn 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.
- kragen 2y agothat's pretty nice! 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