This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-17
Channels
- # announcements (7)
- # architecture (12)
- # babashka (5)
- # bangalore-clj (4)
- # beginners (70)
- # biff (23)
- # calva (21)
- # clojure (130)
- # clojure-bay-area (3)
- # clojure-berlin (1)
- # clojure-brasil (1)
- # clojure-europe (55)
- # clojure-finland (4)
- # clojure-greece (5)
- # clojure-nl (3)
- # clojure-norway (10)
- # clojurescript (52)
- # code-reviews (4)
- # community-development (1)
- # data-science (7)
- # datahike (6)
- # datomic (1)
- # events (1)
- # figwheel-main (7)
- # fulcro (23)
- # helix (2)
- # honeysql (32)
- # malli (18)
- # membrane (6)
- # nbb (22)
- # nyc (1)
- # off-topic (26)
- # pathom (2)
- # polylith (34)
- # quil (13)
- # releases (1)
- # remote-jobs (4)
- # scittle (1)
- # shadow-cljs (52)
- # sql (24)
- # tools-deps (17)
- # vim (11)
- # web-security (15)
- # xtdb (6)
Given that the form using let
and macroexpand
directly below macroexpands just fine, can anyone explain why the analogous definition following that form errors out during macro expansion?
exorcise.core> (let [term-string "a person"]
(macroexpand
(tm/with-matching-template-symbols ["a *type"`
,term-string]
(declare-inferred-type *type))))
(let*
[*type 'person]
(exorcise.core/declare-inferred-type exorcise.core/*type))
exorcise.core> (defn foo [term-string]
(tm/with-matching-template-symbols ["a *type"
term-string]
(declare-inferred-type *type)))
Unexpected error (NoSuchMethodException) macroexpanding tm/with-matching-template-symbols at (*cider-repl Cogex/exorcise:localhost:45999(clj)*:112:18).
exorcise.core$foo$eval6498__6499.<init>()
exorcise.core>
FWIW, here are relevant definitions.
(defn tokens->quoted-symbol [string]
(list 'quote (read-string (clojure.string/replace string " " "_"))))
;;; When you want symbols, it can be convenient to get them directly.
;;; (If you want a mixture of strings and symbols, use both the macro and function above.)
(defmacro with-matching-template-symbols [[template input-form]
& body]
(let [bindings-hashmap (eval
(match-template template input-form))]`
(when-not (= bindings-hashmap :fail)
(let [symbols-hashmap (zipmap (keys bindings-hashmap)
(map tokens->quoted-symbol (vals bindings-hashmap)))
bindings-list (into []
(apply concat ; flatten goes to far here, destroys quoting.
(into [] symbols-hashmap)))]
(let ~bindings-list`
;; Evaluate the body.
~@body)))))
you're doing (eval
(match-template template input-form))` when macroexpanding. In you failing example term-string has no value, so I don't know what ~input-form
could look like
that's not the error I get when I try and run the code you've pasted here. The first error I get is
No such var: macro/term-string
(I'm evaling it in a ns called macro
). I can fix that by quoting term-string
in the macro expand call.
(let [term-string "a person"]
(macroexpand `(with-matching-template-symbols ["a *type" 'term-string]
(declare-inferred-type *type))))
I then didn't have a definition for match-template
so I defined this
(defn match-template [a b] {'*type 'person})
The error seems to be coming from your call to eval
which I'm not sure I understand why it's there. It looks like it's trying to call match-template
to get some information at macroexpansion time? If that's true then changing the code to just calling the function makes the problem go away.
(defmacro with-matching-template-symbols [[template input-form]
& body]
(let [bindings-hashmap (match-template template input-form)]
(when-not (= bindings-hashmap :fail)
(let [symbols-hashmap (update-vals bindings-hashmap tokens->quoted-symbol)
bindings-list (into [] cat symbols-hashmap)]
`(let ~bindings-list
;; Evaluate the body.
~@body)))))
also, I tidied up a couple of bits that looked weird.@l0st3d Losing the (leftover/crufty/embarrassing) eval
gets past the error I'd reported. And thanks for the instructive tidying up.
Now I see a different error where I try to use the macro below that calls the improved macro above. The intended binding seems inaccessible.
exorcise.core> *(defmacro process-variable-term [term-string]*
``(tm/with-matching-template-symbols ["a *type"`
`~term-string]`
`(declare-inferred-type *type)))`
#'exorcise.core/process-variable-term
exorcise.core> (process-variable-term "a person")
Syntax error compiling at (*cider-repl Cogex/exorcise:localhost:44009(clj)*:177:16).
No such var: exorcise.core/*type
exorcise.core>
I'm now wondering if I've just brought too many macro expectations from Common Lisp, where this (e.g.) works:
cl-user(20): *(defmacro with-bindings-list (bindings-list &body body)*
``(let ,bindings-list`
`,@body))`
with-bindings-list
cl-user(21): *(with-bindings-list ((x 1)) x)*
1
cl-user(22): *(setf the-bindings '((x 2)))*
((x 2))
cl-user(23): *(eval
(with-bindings-list ,the-bindings x))*`
2
cl-user(24):
Apparently Clojure treats the final analogous form below differently.
exorcise.core> *(defmacro with-bindings-list [bindings-list & body]*
``(let ~bindings-list`
`~@body))`
#'exorcise.core/with-bindings-list
exorcise.core> *(with-bindings-list [x 1] x)*
1
exorcise.core> *(def the-bindings '[x 2])*
#'exorcise.core/the-bindings
exorcise.core> *(eval
(with-bindings-list ~the-bindings x))*`
Syntax error compiling at (*cider-repl Cogex/exorcise:localhost:44009(clj)*:169:16).
No such var: exorcise.core/x
exorcise.core>
I've played around with different combinations of qualified vs. simple x
for occurrences in (with-bindings-list [x 1] x)
, without success.
At this point, an example might help me build confidence. Are you familiar with any Clojure macro (like my with-matching-template-symbols
) that will establish a local binding for a symbol (like my term-string
) passed via a parameter (like my input-form
) to the macro's calling function (like my process-variable-term
)?
@U65G9MPCK using triple backticks around code makes it a lot easier to read than however you are adding code into your posts right now:
exorcise.core> (defmacro with-bindings-list [bindings-list & body]
`(let ~bindings-list
~@body))
#'exorcise.core/with-bindings-list
exorcise.core> (with-bindings-list [x 1] x)
1
exorcise.core> (def the-bindings '[x 2])
#'exorcise.core/the-bindings
exorcise.core> (eval `(with-bindings-list ~the-bindings x))
Syntax error compiling at (*cider-repl Cogex/exorcise:localhost:44009(clj)*:169:16).
No such var: exorcise.core/x
exorcise.core>
(also, please don't post walls of text/code to the main channel -- keep it in a thread)this is a case where it might actually be easier to construct the output with list
rather than using `
yeah, if you constructed the form passed to eval in a way that didn't namespace qualify symbols automatically it would work
@U0NCTKEV8 @U064X3EF3 So, this is nice.
exorcise.core> (eval `(with-bindings-list ~the-bindings ~'x))
2
Attempting to apply the same guidance to my function, below, ...
(defmacro with-matching-template-symbols [[template input-form]
& body]
(let [bindings-hashmap (match-template template input-form)]
(when-not (= bindings-hashmap :fail)
(let [symbols-hashmap (update-vals bindings-hashmap tokens->quoted-symbol)
bindings-list (into [] cat symbols-hashmap)]
;; Syntax quote (`) namespaces symbols, which we don't want.
;; `(let ~bindings-list
;; ~@body)
(cons 'let
(cons bindings-list
body))))))
...I still have trouble. REPL message on C-M-X in Cider:
Syntax error macroexpanding with-matching-template-symbols at (*cider-repl Cogex/template-matcher:localhost:45323(clj)*:1060:1).
Don't know how to create ISeq from: clojure.lang.Symbol
From the backtrace (below), it looks like the compiler is pushing through the body's full execution trace, then complaining about a symbol where it wants a string.
2. Unhandled clojure.lang.Compiler$CompilerException
Error compiling *cider-repl Cogex/template-matcher:localhost:45323(clj)* at (1060:1)
#:clojure.error{:phase :macro-syntax-check,
:line 1060,
:column 1,
:source
"*cider-repl Cogex/template-matcher:localhost:45323(clj)*",
:symbol with-matching-template-symbols}
Compiler.java: 7027 clojure.lang.Compiler/macroexpand1
Compiler.java: 7110 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 6137 clojure.lang.Compiler$BodyExpr$Parser/parse
Compiler.java: 5479 clojure.lang.Compiler$FnMethod/parse
Compiler.java: 4041 clojure.lang.Compiler$FnExpr/parse
Compiler.java: 7122 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 7112 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 38 clojure.lang.Compiler/access$300
Compiler.java: 596 clojure.lang.Compiler$DefExpr$Parser/parse
Compiler.java: 7124 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 7198 clojure.lang.Compiler/eval
Compiler.java: 7149 clojure.lang.Compiler/eval
core.clj: 3215 clojure.core/eval
core.clj: 3211 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 833 java.lang.Thread/run
1. Caused by java.lang.IllegalArgumentException
Don't know how to create ISeq from: clojure.lang.Symbol
RT.java: 557 clojure.lang.RT/seqFrom
RT.java: 537 clojure.lang.RT/seq
core.clj: 139 clojure.core/seq
core.clj: 139 clojure.core/seq
core.clj: 41 template-matcher.core/strip-leading-chars
core.clj: 39 template-matcher.core/strip-leading-chars
core.clj: 95 template-matcher.core/read-token
core.clj: 94 template-matcher.core/read-token
core.clj: 160 template-matcher.core/match-template
core.clj: 146 template-matcher.core/match-template
RestFn.java: 425 clojure.lang.RestFn/invoke
REPL: 236 template-matcher.core/with-matching-template-symbols
REPL: 234 template-matcher.core/with-matching-template-symbols
RestFn.java: 146 clojure.lang.RestFn/applyTo
Var.java: 705 clojure.lang.Var/applyTo
Compiler.java: 7010 clojure.lang.Compiler/macroexpand1
Compiler.java: 7110 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 6137 clojure.lang.Compiler$BodyExpr$Parser/parse
Compiler.java: 5479 clojure.lang.Compiler$FnMethod/parse
Compiler.java: 4041 clojure.lang.Compiler$FnExpr/parse
Compiler.java: 7122 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 7112 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 38 clojure.lang.Compiler/access$300
Compiler.java: 596 clojure.lang.Compiler$DefExpr$Parser/parse
Compiler.java: 7124 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 7198 clojure.lang.Compiler/eval
Compiler.java: 7149 clojure.lang.Compiler/eval
core.clj: 3215 clojure.core/eval
core.clj: 3211 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 833 java.lang.Thread/run
@U65G9MPCK Sorry, I've been afk. I think the error is in whatever match-template
does. Specifically,
core.clj: 41 template-matcher.core/strip-leading-chars
I think you're passing a symbol to strip-leading-chars
where maybe it wants a string? or at least something it's going to call seq
on??the syntax quote stuff won't apply above, syntax quote only namespace qualifies literal symbols
if you're not already, you might find it helpful to examine the expansion with something like (pprint (macroexpand '(with-matching-template-symbols ...))
so for (foo ~@bar)` foo will be namespace qualified but any symbols within bar will not be
@U064X3EF3 The error comes during macro expansion, so I don't know how to test it that way. macroexpand-1 doesn't show much.
ah, gotcha
Ok, this works now:
(defmacro process-variable-term [term-string]
(cons 'with-matching-template-symbols
(cons ["a *type"
term-string]
'((declare-inferred-type *type)
(type->variable *type)))))
Is there a non-namespacing version of syntax quote somewhere? I have a lot of macros to cons up, at this point. 🙂
syntax quote will only namespace literals. So where you've written
(cons 'let
(cons bindings-list
body))
you could write
`(let ~bindings-list
~@body)
it won't traverse the contents of bindings-list
and namespace all the symbols it finds.So maybe you could write something like this?
(defmacro process-variable-term [term-string]
`(with-matching-template-symbols ["a *type" ~term-string]
(declare-inferred-type ~'*type)
(type->variable ~'*type)))
In my time writing macros I've made the mistake of creating anaphoric macros like that, and ended up wishing I hadn't. It's usually better to be explicit about the names you're creating so you can avoid clashes.@l0st3d Yes, that works also. I think I should be able to keep my code clean, now. 🙂 THANK YOU !!
Hello! Is there a simple way in clojure to group a sequence of strings by a separator? This feels like an easy clojure task, but my brain is failing me. For example, let’s say I have the sequence:
'("BEGIN" "a" "b" "c" "d" "END" "BEGIN" "foo" "bar" "END" "BEGIN" "c" "l" "j" "cool" "END")
And I would, ideally, group this into a sequence of three sequences:
'(("BEGIN" "a" "b" "c" "d" "END") ("BEGIN" "foo" "bar" "END") ("BEGIN" "c" "l" "j" "cool" "END"))
Is there a straightforward way to do this?reduce is one way:
(second
(reduce
(fn [[curr so-far] s]
(if (= s "END")
[[] (conj so-far (conj curr s))]
[(conj curr s) so-far]))
[[] []]
'("BEGIN" "a" "b" "c" "d" "END" "BEGIN" "foo" "bar" "END" "BEGIN" "c" "l" "j" "cool" "END")))
@U011DMQ8DSS Pretty sure there must be a more idiomatic solution though. Perhaps someone else will pitch in.
core=> (->> ["BEGIN" "a" "b" "c" "d" "END" "BEGIN" "foo" "bar" "END" "BEGIN" "c" "l" "j" "cool" "END"]
(partition-by #{"END"})
(partition-all 2)
(map (partial apply concat)))
(("BEGIN" "a" "b" "c" "d" "END")
("BEGIN" "foo" "bar" "END")
("BEGIN" "c" "l" "j" "cool" "END"))
For the second example (and to betray my clojure newness):
would (map (partial apply concat))
be equivalent to (map #(apply concat %))
?
Running through the code, it looks to give the same results, but I might be missing some nuance?
This question of taking/dropping/partitioning upto some condition comes up quite often, but often isn't intuitive to solve with core fns. I think https://github.com/weavejester/medley take-upto
and drop-upto
fns can solve this sort of problem quite nicely:
(->> ["BEGIN" "a" "b" "c" "d" "END" "BEGIN" "foo" "bar" "END" "BEGIN" "c" "l" "j" "cool" "END"]
(iterate #(m/drop-upto #{"END"} %))
(map #(m/take-upto #{"END"} %))
(take-while seq))
;; => (("BEGIN" "a" "b" "c" "d" "END") ("BEGIN" "foo" "bar" "END") ("BEGIN" "c" "l" "j" "cool" "END"))
In @U11BV7MTK's solution, the case of the final group missing a closing tag raises an interesting and meaningful difference if you replace partition-all
with partition
.
(let [m ["BEGIN" "a" "b" "c" "d" "END"
"BEGIN" "foo" "bar" "END"
"BEGIN" "c" "l" "j" "cool"]
group (fn [part-fn m]
(->> m
(partition-by #{"END"})
(part-fn 2)
(map (partial apply concat))))]
(prn (group partition-all m))
; => (("BEGIN" "a" "b" "c" "d" "END")
; ("BEGIN" "foo" "bar" "END")
; ("BEGIN" "c" "l" "j" "cool"))
(prn (group partition m))
; => (("BEGIN" "a" "b" "c" "d" "END")
; ("BEGIN" "foo" "bar" "END"))
)
spec solution
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def ::group (s/cat :begin #{"BEGIN"} :body (s/+ string?) :end #{"END"}))
:user/group
user=> (s/conform ::group ["BEGIN" "A" "B" "C" "END"])
{:begin "BEGIN", :body ["A" "B" "C"], :end "END"}
could that easily be extended to a s/coll-of
solution to handle the original input? (forget how great the spec regex style stuff is)
(s/coll-of would result in a collection of groups, but the original input in the question is "flat")
(def session (atom {}))
(swap! session assoc 123 123)
; Execution error (ClassCastException) at app.freeotp/eval32622 (REPL:2268).
; clojure.lang.LazySeq cannot be cast to clojure.lang.Associative
why? show ClassCastException
If you're not sure why this is happening, maybe try some puts debugging:
(swap! session #(do (prn %) (assoc % 123 123)))
At least you'll learn what's there instead of the expected map.Or if you want to find out where the value comes from, I guess something like this?
(require '[clojure.stacktrace :as st])
(def a (atom {} :validator
(fn [v]
(st/print-stack-trace (Exception.))
(println "New value for atom: " v)
true)))
(defn test []
(swap! a assoc 1 1))
(test)
;; Will print stacktrace here
$ clj
Clojure 1.11.1
user=> (def s (atom {}))
#'user/s
user=> (swap! s assoc 123 123)
{123 123}
user=> user=>
no problem hereCan I safely replace #(clojure.pprint/pprint (with-out-str %))
with prn-str
or can they give different results for a particular input? They seem to be interchangable but the implementations take different paths so I'm wondering if I'm missing something
pprint will add new lines and respond to other pretty printing directives where prn will not
This particular case doesn't define any directives but I didn't think about the new lines, thanks 🙂 > with-out-str is a macro, can't comp it I didn't mean a literal comp, yes, but good point, especially since we're in #C053AK3F9! I fixed it, thanks 🙂
@l0st3d Losing the (leftover/crufty/embarrassing) eval
gets past the error I'd reported. And thanks for the instructive tidying up.
Now I see a different error where I try to use the macro below that calls the improved macro above. The intended binding seems inaccessible.
exorcise.core> *(defmacro process-variable-term [term-string]*
``(tm/with-matching-template-symbols ["a *type"`
`~term-string]`
`(declare-inferred-type *type)))`
#'exorcise.core/process-variable-term
exorcise.core> (process-variable-term "a person")
Syntax error compiling at (*cider-repl Cogex/exorcise:localhost:44009(clj)*:177:16).
No such var: exorcise.core/*type
exorcise.core>
I'm now wondering if I've just brought too many macro expectations from Common Lisp, where this (e.g.) works:
cl-user(20): *(defmacro with-bindings-list (bindings-list &body body)*
``(let ,bindings-list`
`,@body))`
with-bindings-list
cl-user(21): *(with-bindings-list ((x 1)) x)*
1
cl-user(22): *(setf the-bindings '((x 2)))*
((x 2))
cl-user(23): *(eval
(with-bindings-list ,the-bindings x))*`
2
cl-user(24):
Apparently Clojure treats the final analogous form below differently.
exorcise.core> *(defmacro with-bindings-list [bindings-list & body]*
``(let ~bindings-list`
`~@body))`
#'exorcise.core/with-bindings-list
exorcise.core> *(with-bindings-list [x 1] x)*
1
exorcise.core> *(def the-bindings '[x 2])*
#'exorcise.core/the-bindings
exorcise.core> *(eval
(with-bindings-list ~the-bindings x))*`
Syntax error compiling at (*cider-repl Cogex/exorcise:localhost:44009(clj)*:169:16).
No such var: exorcise.core/x
exorcise.core>
I've played around with different combinations of qualified vs. simple x
for occurrences in (with-bindings-list [x 1] x)
, without success.
At this point, an example might help me build confidence. Are you familiar with any Clojure macro (like my with-matching-template-symbols
) that will establish a local binding for a symbol (like my term-string
) passed via a parameter (like my input-form
) to the macro's calling function (like my process-variable-term
)?
I'm looking for something similar to cond->
but whose predicates are functions of the cond's input like
(cond-> [] pred1 do-something1 pred2 do-something2)
where pred1
would be something like
(defn pred1 [v] (> (count v) 2))
I mean, pred1
is a function of what is being threaded (the vector, in this case).
If such macro does not exist, what are the workarounds?We have condp->
(and condp->>
) in our "commons" library but we have moved away from using them as they make code harder to understand more often than they improve things.
https://github.com/worldsingles/commons/blob/master/src/ws/clojure/extensions.clj#L24-L48

What do you do instead? What are the suggestions? It is a pattern I see very often that I'd like to learn a more definitive solution
What we found was that we almost never threaded the result into additional predicates: only the initial expression:
(condp-> expr
some-pred some-transform)
was somewhat common but
(condp-> expr
pred1 transform1
pred2 transform2
.. ..)
was increasingly rare as the number of predicates grew.
So it was usually clearer to just use actual conditionals (`if`, cond
) or put expr
in a let
and do (cond-> x (pred x) transform)
That said, I believe there is some consideration for including something like this in a future version of Clojure... https://clojure.atlassian.net/browse/CLJ-2732
I see. So, there were some legitimate uses for condp->
, right?
Thank you for this very complete answer!
"legimate" is subjective -- does it make the code easier to read than the alternatives? Some people might say "yes", others might say "no".
That CLJ ticket is about a situation where the predicate is the same in all cases: keep threading while the value is "valid" under some specific predicate, rather than threading each result through each different predicate.
You could compose multiple predicates into one. This example (written on phone, maybe buggy) assumes you don't want to mess with the original predicates, instead wrapping them up in a helper to only test on truthy input and pass the input forward on success.
(let [and-pred (fn [pred]
(fn [x] (and x (pred x) x))))]
(when (-> x
(and-pred pred1)
(and-pred pred2)
(and-pred pred3) (foo x))
This macro call works, ...
exorcise.core> (<<- (foobar nil nil))
foobar
...but Clojure complains about this macro I've written to use it.
exorcise.core> (defmacro declare-predicate-for-Prolog (predicate)
`(<<- (~'predicate nil nil)))
Syntax error macroexpanding defmacro at (*cider-repl Cogex/exorcise:localhost:44009(clj)*:674:16).
Don't know how to create ISeq from: clojure.lang.Symbol
Any insights?Here's the backtrace:
2. Unhandled clojure.lang.Compiler$CompilerException
Error compiling *cider-repl Cogex/exorcise:localhost:44009(clj)* at (674:16)
#:clojure.error{:phase :macro-syntax-check,
:line 674,
:column 16,
:source
"*cider-repl Cogex/exorcise:localhost:44009(clj)*",
:symbol defmacro}
Compiler.java: 7027 clojure.lang.Compiler/macroexpand1
Compiler.java: 7092 clojure.lang.Compiler/macroexpand
Compiler.java: 7178 clojure.lang.Compiler/eval
Compiler.java: 7149 clojure.lang.Compiler/eval
core.clj: 3215 clojure.core/eval
core.clj: 3211 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 833 java.lang.Thread/run
1. Caused by java.lang.IllegalArgumentException
Don't know how to create ISeq from: clojure.lang.Symbol
RT.java: 557 clojure.lang.RT/seqFrom
RT.java: 537 clojure.lang.RT/seq
RT.java: 687 clojure.lang.RT/cons
core.clj: 29 clojure.core/cons
core.clj: 472 clojure.core/defmacro/add-implicit-args
core.clj: 481 clojure.core/defmacro/add-args
core.clj: 482 clojure.core/defmacro
core.clj: 454 clojure.core/defmacro
RestFn.java: 146 clojure.lang.RestFn/applyTo
Var.java: 705 clojure.lang.Var/applyTo
Compiler.java: 7010 clojure.lang.Compiler/macroexpand1
Compiler.java: 7092 clojure.lang.Compiler/macroexpand
Compiler.java: 7178 clojure.lang.Compiler/eval
Compiler.java: 7149 clojure.lang.Compiler/eval
core.clj: 3215 clojure.core/eval
core.clj: 3211 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 833 java.lang.Thread/run
(predicate)
needs to be [predicate]
. Clojure uses vector literals for the argument list
could be others. your unquoting of ~'predicate
is probably not what you want if you are taking a predicate arg
@U11BV7MTK Re [predicate]
, ouch. (Probably too much CL history, not enough sleep. ;-))
But with that change the output assertion is (predicate nil nil)
, not (foo nil nil)
as intended.
Not sure what to do. <<-
is a macro (that calls a macro in the Prolog interface).
My predicate here (for assertion to Prolog) is foo
, in case that's not obvious. Unquoting isn't getting me foo
, though.