One of my favourite pieces of code is a Lisp REPL in Lisp:
(defun repl()
(loop (print (eval (read)))))One of my favourite pieces of code is a Lisp REPL in Lisp:
(defun repl()
(loop (print (eval (read))))) (-> read eval print loop)(->) 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.
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). @(-> ctx
:hypercrud.browser/fiddle
(reactive/cursor [:fiddle/ident])
(->> (reactive/fmap name)))
another (-> [10 11]
(conj 12)
(as-> xs (map - xs [3 2 1]))
(reverse))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-placeholde...
It is totally possible to write custom -> macro that works correctly as used in my example.
The threading macro is great, but the GP one-liner tells me more about lisp.
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..."
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"
[0]https://docs.microsoft.com/en-us/dotnet/fsharp/language-refe...
Makes most sense if you think of HTML
<html> <body> <div> </div> </body> </html>
would compose as
compose( html, body, div )
(defmacro -> (&rest args)
(loop for item in (reverse args)
for result = (list item) then (list item result)
finally (return result)))Though I guess that wouldn't be valid lisp if you tried to express it literally.
while True:
print(eval(input(">>> "))) 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 syntaxPython'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.
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.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.