Very interesting work to support babahska. Related to that, what is the current status of compiling a meander application with graalvm? It would be nice to use meander in a clojure compiled app. I didn't test it, but I suspect that currently, a clojure app will fail to compile if it depends on meander. But I also suspect that the changes to support babashka will help in compiling meander with graalvm.
@jlle I'm not sure why it would fail in GraalVM, I don't see any obstacles
I haven't tried and I'm not deeply familiar with the code.
It's not hard to try it out though. Here is a small CLI: https://github.com/borkdude/puget-cli which should easily be changed to run a meander example.
@borkdude maybe not, I didn't try myself neither. I supposed that if it fails with babashka, the compilation with graalvm will fail too, but I can easily be wrong
Thanks for the suggestion, I don't have the time right now, but definitely I'll try to compile meander
Babashka uses sci which is a Clojure interpreter which you can compile with GraalVM. Running code through sci is not the same as directly compiling it with GraalVM. Some things are support in one and not in the other and vice versa.
I see, good to know, I assumed that if some code runs in babashka, it will compile with graalvm
One example: you cannot execute functions that use clojure.core/eval with graalvm, because eval needs compilation.
But you can do this with sci.
But some things like deftype, etc are not support in sci.
Obviously term rewriting is good for direct optimizations. But if I had a constraint on size, and had to prevent certain things from nesting, I'm guessing that's out of bounds for term rewriting?
@dominicm I don’t think that is necessarily true but maybe a little more context?
@noprompt I'm thinking of writing a clojure minifier, because reasons.
So can't nest #(#()) for example.
@dominicm I'm working on extracting the uberscript functionality from babashka so it also works for JVM. Together with carve (cut out unused vars) this is also a kind of minifier.
I’m thinking, for example, a pair of a peano number indicating the depth and the term
[0 ?term] = ?term
[(s ?nat) ?term] = (recur [?nat ?term*])
> because reasons @dominicm sounds like how I arrived 🙂
@borkdude I’m trying to grind out this interpreter code patch as fast as I can to try out.
TBH, I could probably remove a lot of the internal use of match
which is one part suck and another part not.
sounds exciting :)
It would definitely improve the load time for every one.
What's the use case and what are some of things you are thinking about?
I'm thinking of building a code golfer, and this feels like a fair addition. Maybe it's not though. But it's no fun to be beaten by your colleague who strategically added #() after seeing your solution.
I’ve tried to speed up the compilation of the macros but at some point I’m comfortable with prioritizing the speed of the runtime code over the compiler speed. At the point is where the interpreter should fit in.
Fun :)
I am quite interesting Graal FWIW.
I’m interested to see how well the interpreter runs once the partial evaluation magic kicks in.
Code golf is a young mans game. 😛
There is an open issue for clj-kondo that would help LSP find locals for renaming. This could also be used for renaming locals to minify code
e.g. rename foobar to F
Tangentially related to this discussion: I often use cata
as a subroutine of sorts. When I do this, I've adopted an idiom along the lines of
(m/rewrite something
?n
(m/cata {::number !n})
[!n ...]
[(m/cata {::number !n}) ...]
{::number (m/pred number? ?n)}
blah-blah)
I vaguely remember a conversation in this channel saying that this is a pretty common idiom and that meander might adopt first-class support for it. I'm just curious to follow up on thatI need to find the time to look into these cool things. Long time fan of LSP though I’ve never made the time to put it to use in Emacs.
Good place to stick rewriting.
@noprompt Also check out https://github.com/borkdude/carve for deleting unused vars.
Do you remember what was connected to that? I vaguely remember that but my memory these days, eh, is bad.
heh I sympathize
No, I don't recall much else about the conversation.
It is not a big issue for me.
I imagine that direct support could yield better runtime performance but my use case is not performance sensitive
cata
compilation will get better in time. I’m just barely starting to get time in my life back for hacking on Meander.
The paste few months have been hard on me.
I'm sorry. I hope you don't take my comments as critical. Meander has been a HUGE boon to my productivity and I appreciate all your efforts
> I hope you don’t take my comments as critical Not at all! 🙂
I love this project, this channel, and the little community of we’ve established here around this stuff. I like making people happy and get sad when I can’t. 🙂
In general, the Clojure community is very friendly. Meander community is even more so 🙂
OK I’m like 80% done with an initial interpreter worthy of kicking around.
So just 80% left to go? :)
LOL
I just meant that I have a rough draft that is sturdy enough to use at your own risk. 🙂
I’m trying to minimize the at your own risk part as a courtesy, however. 😂
(ns scratch
(:require [meander.interpreter.epsilon :as m]))
(def search-a
(m/searcher
'(m/re #"(.)(.)(.)" (m/and [?0 ?1 ?2 ?2] [!0 ...]))
(fn [{:syms [?0 !0]}]
[?0 !0])
'(m/re #"f(.*)" [!0 ?0 . !0 ...])
(fn [{:syms [?0 !0]}]
[?0 !0])))
(search-a "foo")
;; => (["foo" ["foo" "f" "o" "o"]] ["oo" ["foo"]])
(search-a "foe")
;; => (["oe" ["foe"]])
Seems like this could work
What do y’all think?
JHOLDBRO-M-C65T.jholdbro=> rlwrap bb --classpath src
Babashka v0.2.3 REPL.
Use :repl/quit or :repl/exit to quit the REPL.
Clojure rocks, Bash reaches.
user=> (require '[meander.interpreter.epsilon :as m])
nil
user=> (def s1 (m/searcher '(m/re #"f(.)(.)" [_ ?x ?x]) #(get % '?x)))
#'user/s1
user=> (s1 "foo")
("o")
user=> (s1 "faa")
("a")
user=> (s1 "f11")
("1")
@borkdude worksIt appears to be very fast.
Well, sort of.
;; Clojure
(with-out-str (time (dotimes [_ 10000] (doall (search-a "foe")))))
"\"Elapsed time: 253.965799 msecs\"\n"
;; Babashka
(with-out-str (time (dotimes [_ 10000] (doall (search-a "foe")))))
"\"Elapsed time: 3284.494238 msecs\"\n
Not sure what’s going on here.
;; Clojure
(with-out-str (time (doall (search-a "foe"))))
"\"Elapsed time: 0.012454 msecs\"\n"
;; Babashka
(with-out-str (time (doall (search-a "foe"))))
"\"Elapsed time: 0.814953 msecs\"\n"
In terms of performance, for this example, interpretation is going to be slower over all, however, it’s also going to be more flexible.
(defn search-b [s]
(me/search s
(me/re #"(.)(.)(.)" (me/and [?0 ?1 ?2 ?2] [!0 ...]))
[?0 !0]
(me/re #"f(.*)" [!0 ?0 . !0 ...])
[?0 !0]))
[(with-out-str (time (dotimes [_ 10000] (doall (search-a "foe")))))
(with-out-str (time (dotimes [_ 10000] (doall (search-b "foe")))))]
;;=>
["\"Elapsed time: 120.945113 msecs\"\n"
"\"Elapsed time: 15.265521 msecs\"\n"]
It’s likely possible to close that gap on this a bit using, say, an approach similar to Egison.
Or using ye olde matrix style pattern matching compilation but, of course, to functions instead of code.
Variables would need to have their names changed to protect the innocent.