TXR Lisp
nongnu.org
nongnu.org
The language might be "objectively" simple, but it's not at all a simple language. There is no user guide, nor is there a nice readable language spec like R7RS. There's a reference manual, and a bunch of StackOverflow examples that look like Perl with S-expressions. I'd love to sit down and work through a reference manual, but who has time for that nowadays?
I love the idea of a Lisp purpose-built for data processing, but practically I don't know what I'll gain by learning this that I don't already have with Python, Zsh, and Gauche Scheme.
Can someone convince me otherwise? What's the killer feature of TXR that makes it worth the effort of learning it the hard way?
Also, what's with the leading @-signs in some of the examples? Does that (try) form delimit some kind of block or region? Why are there some lines that look like bare string literals? It's clever and impressive to manually build a patch that can be applied with Git, but is this solution any cleaner or faster or easier to write or read than the equivalent in Python or Perl or Gauche or Guile or Common Lisp? https://stackoverflow.com/a/37336801/2954547
Having said that -- once you get Prolog and use it for a while, your brain (at least my brain) wants to replace EVERYTHING with Prolog.
You could say that it's simple but not easy
I'm happy to try to use it for Advent of Code 2024, but it would help if I could at least get oriented so I'm not going in totally cold (and thereby likely to fall off the wagon after 3 days because each one takes 2 hours in an unfamiliar language).
The data science use case is particularly interesting and not something I had considered here. Arrow bindings help immensely. Of course at work I'll probably never get a chance to use anything other than Python and R for many years to come; maybe Julia is the most exotic I think I'd ever be able to go, and that's only if I ever hit a performance bottleneck in Python that can't be remediated with Numba.
https://www.kylheku.com/cgit/advent/tree
That gives a flavor of how those kinds of problems can be approached.
The solutions are all self-contained; they don't share any AoC-specific library or anything, and were developed with a throwaway program mindset, where we just solve that problem and don't try to produce anything that is reusable other than by copy paste into the next program.
(fieldrx (regex-compile ;; using a regex object here messes with emacs syntax highlighting
"([^,\"\']*(\"([^\"]|\\\\\")*\"|\'([^\']|\\\\\')*\'|)[^,\"\']*)+"))
I understand that here using the #/.../ regex literal object didn't look right in your Emacs, so you dynamically compiled from a string literal.But that now happens each time you call the function.
Lisp has your back here; we can hoist the compilation of the regex to load time using load-time:
(fieldrx (load-time (regex-compile "...RE...")))
load-time makes a difference in interpreted code, not just compiled files. Even in interpreted code, the regex-compile expression will be evaluated once only and then the cached value used: 1> (dotimes (i 5) (prinl "hi"))
"hi"
"hi"
"hi"
"hi"
"hi"
nil
2> (dotimes (i 5) (load-time (prinl "hi")))
"hi"
nilThose times when it would be nice for the Python-Zsh-Scheme solution to be in one language and program.
> is this solution any cleaner or faster or easier to write or read than the equivalent in Python or Perl or Gauche or Guile or Common Lisp?
I believe so because we can see the salient parts of the diff hunk structure appearing literally in the code, so we know at a glance where it is pulling what. I've not looked at that since 2016 but it's transparent.
On top of that, any Python, Perl, Guile or Common Lisp solution can be transliterated to decent TXR Lisp. There are multiple ways to attack that same problem in TXR, not necessarily using the TXR Pattern Language.
There are "spiritual ties" between TXR Lisp and Common Lisp. There probably isn't another language distinct from Common Lisp that is as similar to Common Lisp as TXR Lisp. The TXR Lisp reference manual mentions ANSI CL numerous times in various Dialect Notes.
There is a translation to TXR Lisp of the CL-WHO HTML generation library called TL-WHO. It's a function-by-function translation that retains most of the structure of the original code. https://www.kylheku.com/cgit/tl-who/about/
If you have CL skills and knowledge, a lot of it will transfer over to TXR Lisp, and vice versa. There will be things you will miss in either direction.
By the way, here is another TXR program that matches unified diffs: diff2err:
https://www.kylheku.com/cgit/diff2err/tree
This reads diff material from standard in and converts it to compiler error format, stored in a file called errors.err (implicitly used by "vim -q" quickfix mode). This is useful for visiting differences in the actual code, with the editor: you can jump to all the places that were changed, and at every location, the diff info appears in diagnostic format: how many lines were changed, and what the original lines are.
The writing style isn't particularly better than the one in the TXR manual.
Both are specifications, and not tutorials.
The Scheme world depends on R7RS for giving the requirements for the portable, common language core.
Since TXR isn't a fragmented language family of incompatible implementations, there isn't any need to have a small document laying out what is common.
Where is the hyperlinked, HTML version of R7RS? Every time I need to look up something in that, I have to use a clunky PDF.
A search "HTML R7RS", shows mostly old posts in mailing lists and forums asking the same question. That and someone's github repo containing what seems to be source for generating a HTML-ized R7RS.
The TXR manual is available in usefully (though imperfectly) hyper-linked HTML, PDF as well as a man page: just "man txr" and /search. When you type (doc 'symbol) in the listener, it jumps your browser to that section of the manual (the externally hosted version, easily retargetable to a local copy by changing the value of *doc-url*.
TXR Lisp – an innovative, original dialect from the Lisp language family - https://news.ycombinator.com/item?id=24449511 - Sept 2020 (1 comment)
TXR Lisp - https://news.ycombinator.com/item?id=22683735 - March 2020 (9 comments)
TXR: An Original, New Programming Language for Convenient Data Munging - https://news.ycombinator.com/item?id=21699927 - Dec 2019 (2 comments)
TXR – A Programming Language for Convenient Data Munging - https://news.ycombinator.com/item?id=19908197 - May 2019 (73 comments)
TXR: An Original, New Programming Language for Convenient Data Munging - https://news.ycombinator.com/item?id=12338441 - Aug 2016 (2 comments)
TXR: A Programming Language for Convenient Data Munging - https://news.ycombinator.com/item?id=8409391 - Oct 2014 (38 comments)
Show HN: Munge your data with TXR - https://news.ycombinator.com/item?id=8020106 - July 2014 (1 comment)
Common lisp verbosity is a feature. It make's it very clear what is happening. Everyone understands.
Apparentlt the author hangs out here, so I'd recommend the author stick in some links to examples there if they don't want to muddy up the introduction page, because I think plenty of people that like lisp (not all, but plenty) will see this as an anti-feature without proof to the contrary.
(if (real-time-stream-p *stdin*)
(put-line (quip)))
Then you will see a random humorous quip on startup.The stream test around the put-line is recommended, otherwise you will see the quip even if the REPL is used in a pipe:
$ echo '(+ 2 2)' | txr
4 (mapdo .start-time.(set 42) obj-list)
(swap [a 2..4] [b 0..2])
This looks gross. Why does no one seem to understand that lisp should not have infix operators?In TXR Lisp, I decided to experiment with a small number of notations, to see whether they could make Lisp coding a bit more ergonomic, similarly to how 'x has helped with (quote x) for over sixty years.
There are rules: the notations have to absolutely fit into the surrounding Lisp.
The notations all have an underlying equivalent tree structure: list headed by a specific symbol.
There must be print-read consistency.
Not all combinations of the underlying structure need to (or should) map to the notation.
1> '(qref a b c d)
a.b.c.d
2> '(qref a b (qref c d))
(qref a b c.d)
3> '(qref (qref a b) (qref c d))
(qref a.b c.d)
4> '(qref 1 0)
(qref 1 0)
5> '(qref 1 a)
(qref 1 a)
6> '(qref a 1)
(qref a 1)
Not every (qref X Y) is blindly printed as X.Y, which would break print-read consistency. Multiple different qref nestings would map to the same notation, and (qref 1 0) would produce the floating-point token 1.0.Of course, some of these notations complicate parsing. When we see a symbol token like a, we cannot just return the symbol, because it could be followed by a dot, in which case we are in (qref a ... syntax, or other possibilities.
Be that as it may, working with this stuff is fine; all in a day's Lisp.