8 ms·
Lisp is a fun language to program in. I learned Lisp after already being familiar with Java / Python and some other languages, which maybe made it even more bea
by Insanity 8y ago
Lisp is a fun language to program in. I learned Lisp after already being familiar with Java / Python and some other languages, which maybe made it even more beautiful.
One of my favourite pieces of code is a Lisp REPL in Lisp:
(defun repl()
(loop (print (eval (read)))))
- keymone 8y agolooks even better with threading in imaginary lisp dialect: (-> read eval print loop)
- earenndil 8y agoI think clojure has that; I could be wrong, though, I've never used clojure.
- intertextuality 8y agoClojure does indeed have -> (thread-first), ->> (thread-last), some->, some->>, cond->, and as->. [0] (->) inserts each form's value between the function name & the first argument in the next form. (->>) inserts each form's value as the last argument in the next form. The latter forms are much more niche and I haven't found need for them yet. [0]: https://clojure.org/guides/threading_macros https://clojure.org/guides/threading_macros
- iterati 8y agoas-> is great for when you have to mix thread-first and thread-last. cond-> is great for building maps where some keys might not be needed: (cond-> {:k1 v1} v2 (assoc :k2 v2) ...) some-> and some->> I don't use as often, but when mixing in some java code that could throw an NPE, these will avoid that and just return nil early (they short-circuit when getting a nil value).
- dustingetz 8y agoYou can next ->> inside ->, took far too many years for me to realize: @(-> ctx :hypercrud.browser/fiddle (reactive/cursor [:fiddle/ident]) (->> (reactive/fmap name))) another (-> [10 11] (conj 12) (as-> xs (map - xs [3 2 1])) (reverse))
- scns 8y agoBucklescript/ReasonML have that too: CLJ:(->)/BS(|.)/RML(->) called Fast Pipe. CLJ:(->>)/BS(|>)/RML(|>) called Pipe. plus some nifty placeholders for other positions: https://reasonml.github.io/docs/en/fast-pipe#pipe-placeholders https://reasonml.github.io/docs/en/fast-pipe#pipe-placeholde...
- keymone 8y agoIt does, sort of. As another commenter pointed out, -> chains the operands at the beginning, but also ‘loop’ form requires list of bindings. It is totally possible to write custom -> macro that works correctly as used in my example.
- samatman 8y agoAgree to disagree; to write lisp one must know how to read it. The threading macro is great, but the GP one-liner tells me more about lisp.
- gnulinux 8y agoLisp is all about being able to compile the latter to the former in compile-time, if you want it. That's the major problem lisp solves.
- samatman 8y agoHard agree! Still one is the latter and the other, the former. Hence I think the first tells more of the lisp story, with just a few more parens. ;-) "Why is it called REPL when the code says LPER? Well..."
- kazinator 8y agoWhy is it called "root mean square" when you square first, then take the mean, and then the root?
- ves 8y agoWe can just cut straight to “why is function composition backwards?”
- gnulinux 8y ago`(root (mean (square x)))` Is this more readable? `x ~> square . mean . root` Where `~>` "sends" a value to a function `x ~> f := f(x)` and `.` is the "backwards" function composition `f . g := \x (g (f x)) I think I prefer the "backwards" notation ("root mean square"), but I can see the appeal of "square mean root"
- Silfen 8y ago
- aidenn0 8y ago(defmacro -> (&rest args) (loop for item in (reverse args) for result = (list item) then (list item result) finally (return result)))
- keymone 8y agoNo longer imaginary. Power of LISP right there.
- Macha 8y agoPython 3 for comparison: while True: print(eval(input(">>> ")))
- frostoov 8y agoNot really: ovov@ovov ~> cat repl.py while True: print(eval(input(">>> "))) ovov@ovov ~> python3 repl.py >>> x = 1 Traceback (most recent call last): File "repl.py", line 2, in <module> print(eval(input(">>> "))) File "<string>", line 1 x = 1 ^ SyntaxError: invalid syntax
- reikonomusha 8y agoThis is a fundamentally different function that works with strings and not symbolic data structures.
- kbp 8y ago`input` isn't READ, it's READ-LINE. READ reads one Lisp form, even if it's more than one line, and even if there are more than one on one line. Python's `eval` also isn't sufficient here. For example, you cannot enter that loop you wrote at the prompt it provides when you run it, even if you write it on one line. You could use `exec`, but then everything would print as `None`. There's the larger point about forms vs strings and printing readably and such, but this doesn't even provide the same basic functionality that a Python programmer would expect from a REPL.
- 3pt14159 8y agoThat is cool, but it's pretty similar in Ruby. def repl loop { puts( eval gets ) } end I guess I just prefer Ruby for general legibility. The same type of bracket everywhere makes pairing them mentally an error-prone chore. At least for yours truly.
- reikonomusha 8y agoThis is actually a very different piece of code. puts and gets are string functions. read and print are code deserializers and serializers. eval is a function that takes a data structure representing code (as deserialized by read) and computes its value as a data structure, and serializes it. While you might get the same effect as a user, the mechanics and metacircularity are lost.
- deleted 8y ago[deleted]
- LgWoodenBadger 8y agoI've always thought (probably because I'm not that smart) that REPL really should have been coined as REPR instead. Though I guess that wouldn't be valid lisp if you tried to express it literally.