You might be able to rewrite the pull query as a quoted pattern and then build an interpreter with it.
Using the meander.interpreter.epsilon
namespace. I can sort of imagine how to do it but I’m a bit in the weeds with some other things.
On a separate topic, I’m interested in potentially slightly tweaking m/app
in zeta
(which I’m now making progress on based off existing work and the interpreter).
(m/apply fn-pattern args-pattern ret-pattern)
;; Query semantics
;; ---------------
;;
;; Target is applied to a function yielded by `fn-pattern` and
;; `args-pattern` without modifying bindings. The return value is
;; queried against `ret-pattern`.
;;
;; Example
;; -------
;;
;; (m/find 1 (m/apply ~clojure.core/+ [2 3] 6) true)
;; ;; => true
;;
;; Yield semantics
;; ---------------
;;
;; Yields the result of applying a funtion yielded by `fn-pattern` to
;; arguments yielded by `args-pattern` if the result successfully
;; queries against `ret-pattern`.
;;
;; Example
;; -------
;;
;; (m/generate (m/apply ~clojure.core/+ [2 3] _))
;; ;; => 5
Part of the reason I’m moving in the direction of using ~
like this is make it explicit where Clojure interop happens.
This has some similar motivations as project
to do things a bit more safely than ~
is hackishly used for today.
(m/find [2 3 5]
[?x ?y (m/apply ~clojure.core/+ [?x ?y] _)]
true)
Instead of
(m/find [2 3 5]
[?x ?y ~(+ ?x ?y)]
true)
fwiw, I like the general approach
does this mean that fns with multiple args will always get invoked through clojure.core/apply ?
For m/apply
this would be the semantic. Separately, I was thinking we could have
(m/invoke fn-pattern arg-pattern* ret-pattern)
for the case where you don’t want to use clojure.core/apply
.But, I’m still thinking about the semantics of these things.
My thoughts about using ~
are really the most important ones.
(To me.)
(m/invoke ~(partial apply some-fn) ?x)
could be just fine.
I was noticing that I’m not really happy with
(m/app (partial apply +) [!xs ...])
on the right.