When I re-implement a macro written in Scheme with Clojure, I get into a trouble.
The macro tries to load pairs of testing data into a all-tests var for later use.
Because the arguments for the macro is variable-length and contains special undefined symbol, i.e. =>, I simply don't know how to parse it like what Scheme syntax-rules does.
Scheme Version:
(define all-tests '())
;;; load tests into all-tests
(define-syntax add-tests-with-string-output
(syntax-rules (=>)
[(_ test-name [expr => output-string] ...)
(set! all-tests
(cons
'(test-name [expr string output-string] ...)
all-tests))]))
(add-tests-with-string-output "integers"
[0 => "0\n"]
[1 => "1\n"]
[-1 => "-1\n"]
[10 => "10\n"]
[-10 => "-10\n"]
[2736 => "2736\n"]
[-2736 => "-2736\n"]
[536870911 => "536870911\n"]
[-536870912 => "-536870912\n"]
)
My current unsuccessful Clojure Version:
(def all-tests (atom '()))
(defmacro add-tests-with-string-output
[test-name & body]
`(loop [bds# (list body)]
(when-not (empty? bds#)
(println (first bds#))
(recur (rest bds#)))))
Ps: I am using println to test my code right now. When it works, I will try to do the parsing and loading work.
The first macro forms a loop and the second one a doseq (so is simpler). Both should behave the same. Also I find it a good idea to extract as much logic out of macros into auxiliary functions. Functions are easier to debug, test and write. If the macro were a bit more complicated I might have left even less logic in it.
(def all-tests (atom '()))
(defn add-test [test-name expr output-string]
(swap! all-tests #(cons (list test-name [expr output-string]) %)))
(defmacro add-tests-with-string-output
[test-name & body]
;`(loop [bds# '(~#body)]
`(loop [bds# '~body] ; edit
(when-not (empty? bds#)
(let [bd# (first bds#)
expr# (first bd#)
output-string# (last bd#)]
(add-test ~test-name expr# output-string#)
(recur (rest bds#))
))))
(defmacro add-tests-with-string-output2
[test-name & body]
;`(doseq [bd# '(~#body)]
`(doseq [bd# '~body] ; edit
(let [expr# (first bd#)
output-string# (last bd#)]
(add-test ~test-name expr# output-string#))))
user=> (add-tests-with-string-output "test1" [0 => "0\n"] [1 => "1\n"])
nil
user=> (add-tests-with-string-output2 "test2" [0 => "0\n"] [1 => "1\n"])
nil
user=> #all-tests
(("test2" [1 "1\n"]) ("test2" [0 "0\n"]) ("test1" [1 "1\n"]) ("test1" [0 "0\n"]))
After trials and errors, finally I figure out how to solve it.
First use Destructuring to tackle the arguments of variable-length;
later do not use Syntax-Quoting, i.e. backquote `, inside the macro, because if so, once you need to unquote ~ the argument, i.e. body, you will get error msg like this due to the special symbol =>:
CompilerException java.lang.RuntimeException: Unable to resolve
symbol: => in this context
Below is my solution.
If you get better one, or you know the reason why Syntax-Quote and Unquote go wrong, please let me know.
;;; load tests into all-tests
(def all-tests (atom '()))
(defmacro add-tests-with-string-output
[test-name & body]
(loop [bds body, tests '()]
(if (empty? bds)
(do
(swap! all-tests #(cons (cons test-name tests) %))
nil)
(let [pair (first bds),
input (first pair)
output (last pair)]
(recur (rest bds) (cons (list input ''string output) tests))))))
Related
I've been struggling to create a macro that'll allow me to dynamically bind whatever is in the &env into a binding form and then delegate to a pry like function to open a REPL that can see those bound &env symbols.
My simplistic pry func, which works as expected
(defn pry []
(print (str "pry(" *ns* ")> "))
(flush)
(let [expr (read)]
(when-not (= expr :exit)
(println (eval expr))
(recur))))
Using the pry func:
clojure-noob.core=> (def a 1)
#'clojure-noob.core/a
clojure-noob.core=> (pry)
pry(clojure-noob.core)> (+ a 1)
2
pry(clojure-noob.core)> :exit
nil
clojure-noob.core=>
My attempt at creating a dynamic invocation of binding:
(defmacro binding-pry []
(let [ks (keys &env)]
`(let [ks# '~ks
vs# [~#ks]
bs# (vec (interleave ks# vs#))]
(binding bs# (pry)))))
However, this fails because the inner symbol bs# is not expanded to an actual vector but instead is the generated symbol and binding tosses a clojure.core/binding requires a vector for its binding exception.
clojure-noob.core=> (let [a 1 b 2] (binding-pry))
Syntax error macroexpanding clojure.core/binding at (/tmp/form-init14332359378145135257.clj:1:16).
clojure.core/binding requires a vector for its binding in clojure-noob.core:
clojure-noob.core=>
The code quoted form with a debug print, the bs# symbol is resolved when printing but I don't know how to make it resolve to a vector when constructing the binding form.
(defmacro binding-pry []
(let [ks (keys &env)]
`(let [ks# '~ks
vs# [~#ks]
bs# (vec (interleave ks# vs#))]
(println bs#)
`(binding bs# (pry)))))
clojure-noob.core=> (let [a 1 b 2] (binding-pry))
[a 1 b 2]
(clojure.core/binding clojure-noob.core/bs__2464__auto__ (clojure-noob.core/pry))
clojure-noob.core=>
I'm very confident I'm tackling this incorrectly but I don't see another approach.
The Joy of Clojure demonstrates a break macro that does this already. I can't reproduce its source here, because it's EPL and not CC. But you can see its source at https://github.com/joyofclojure/book-source/blob/b76ef15/first-edition/src/joy/breakpoint.clj. It refers to a contextual-eval function as well: https://github.com/joyofclojure/book-source/blob/b76ef15/first-edition/src/joy/macros.clj#L4-L7.
A first step towards improving your attempt could be writing:
(defmacro binding-pry []
(let [ks (keys &env)]
`(binding [~#(interleave ks ks)] (pry))))
This still doesn't work because binding expects that the symbols can be resolved to existing dynamic vars. To tackle this problem you could make binding-pry introduce such vars as shown below:
(defmacro binding-pry []
(let [ks (keys &env)]
`(do
~#(map (fn [k] `(def ~(with-meta k {:dynamic true}))) ks)
(binding [~#(interleave ks ks)] (pry)))))
But this can have undesirable side-effects, like polluting the namespace with new var-names or making existing vars dynamic. So I would prefer an approach like the one mentioned in amalloy's answer but with a better implementation of eval-in-context (see my comment there).
To write a self-contained answer based on your pry function, let's first define eval-in which evaluates a form in an environment:
(defn eval-in [env form]
(apply
(eval `(fn* [~#(keys env)] ~form))
(vals env)))
Then let's modify pry to take an environment as an argument and use eval-in instead of eval:
(defn pry [env]
(let [prompt (str "pry(" *ns* ")> ")]
(loop []
(print prompt)
(flush)
(let [expr (read)]
(when-not (= expr :exit)
(println (eval-in env expr))
(recur))))))
An equivalent, less primitive version could be:
(defn pry [env]
(->> (repeatedly (let [prompt (str "pry(" *ns* ")> ")]
#(do (print prompt) (flush) (read))))
(take-while (partial not= :exit))
(run! (comp println (partial eval-in env)))))
Now we can define binding-pry as follows:
(defmacro binding-pry []
`(pry ~(into {}
(map (juxt (partial list 'quote) identity))
(keys &env))))
Finally, here is a direct/"spaghetti" implementation of binding-pry:
(defmacro binding-pry []
(let [ks (keys &env)]
`(->> (repeatedly (let* [prompt# (str "pry(" *ns* ")> ")]
#(do (print prompt#) (flush) (read))))
(take-while (partial not= :exit))
(run! (comp println
#((eval `(fn* [~~#(map (partial list 'quote) ks)] ~%))
~#ks))))))
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)
How do I evaluate this resulting list?
(type (first a))
; => cljs.core/Symbol
(= (first a) '+)
; => true
I suppose more generally how would I get from symbol -> function.
And is this a normal practice in clojure? I can't seem to find anything on it. Perhaps I'm not searching with the correct terms.
You'd normally use eval. But in ClojureScript, you'd need the compiler and standard lib available at runtime. This is only possible if you are making use of self-hosted ClojureScript.
If you are in a self-hosted environment (such as Lumo, Planck, Replete, Klipse, etc.), then eval will just work:
cljs.user=> (require '[clojure.edn :as edn])
nil
cljs.user=> (def a (edn/read-string "(+ 1 3)"))
#'cljs.user/a
cljs.user=> (eval a)
4
Otherwise, you can make use of the facilities in the cljs.js namespace to access self-hosted ClojureScript:
cljs.user=> (require 'cljs.js)
nil
cljs.user=> (cljs.js/eval (cljs.js/empty-state)
a {:eval cljs.js/js-eval :context :expr} prn)
{:value 4}
Note that doing this carries some size considerations: The ClojureScript compiler will be brought with your compiled artifacts into the target environment, and you must also avoid using :advanced, ensuring that the entire cljs.core standard lib and associated metadata is available at runtime.
My answer seems to only work in Clojure, not ClojureScript. See the other answer.
I think you may be looking for resolve.
(defn my-simple-eval [expr]
; Cut the function symbol from the arguments
(let [[f & args] (edn/read-string expr)]
; Resolve f to a function then apply the supplied arguments to it
(apply (resolve f) args)))
(my-simple-eval "(+ 1 3)")
=> 4
The arguments must be bare numbers for this to work though. If you want to allow for sub-expressions, you could make it recursive:
(defn my-simple-eval-rec [expr]
(letfn [(rec [[f & args]]
(->> args
(map (fn [arg]
(if (list? arg)
(rec arg) ; Process the sub-expr
arg)))
(apply (resolve f))))]
(rec (edn/read-string expr))))
(my-simple-eval-rec "(+ 1 (+ 2 5))")
=> 8
If this doesn't suffice though, I don't know of any way other than using eval:
(def a (edn/read-string "(+ 1 3)"))
(eval a)
=> 4
or, if the data is available at the time macros are expanded, you could just wrap the call to read-string to have the data interpreted as normal:
(defmacro my-read-string [expr]
(edn/read-string expr))
(my-read-string "(+ 1 3)")
=> 4
Hi everybody I've been recently trying to learn to a new language and I sort of bumped into Clojure which look like a real interesting language because I've never heard about functional programming, even though I had used JavaScript before that kind of leverages it, well I'm gonna stop with the small talk and get into the problem.
I've been working on solving the https://github.com/gigasquid/wonderland-clojure-katas and more specific on the doublets problem. I think I have came with a solution but it send me the error on the title of this post. I have read about this error and it seems that it triggers when you want the compiler expects a function but it doesn't. Here is the full code of my solution to see if you can help me out with this one:
(ns doublets.solver
(:require [clojure.java.io :as io]
[clojure.edn :as edn]
[clojure.set :as set]))
(def words (-> "words.edn"
(io/resource)
(slurp)
(read-string)))
(defn linked-word [word word-list]
(some #(when (= (count (set/difference (into #{} (seq %))
(into #{} (seq word)))) 1) %)
word-list))
(defn doublets [word1 word2]
(let [n (count word1) v (cons word1 (filter #(= (count %) n)
(remove #{word1} words)))]
(tree-seq #(and (linked-word (% 0) %) (not= (% 0) word2))
#(cons (linked-word (% 0) (rest %))
(remove #{(% 0)} (rest %))) v)))
As you can see cons is a function so the error doesn't seem to be the case described above.
I can reproduce the error after downloading the words.edn file and running with (doublets "bank" "loan"). I think the problem is these expressions:
(% 0)
which you have in a few places. I see that you are cons-ing some things, so that may be a clue. What is (% 0) supposed to do?
If you want the first char, just say (first xyz) or something.
I would also break out the anonymous functions #(...) and give them real names.
Update
My guess seems to be correct as this experiment shows:
(cons 1 [2 3]) => (1 2 3)
(class (cons 1 [2 3])) => clojure.lang.Cons
(vec (cons 1 [2 3])) => [1 2 3]
(class (vec (cons 1 [2 3]))) => clojure.lang.PersistentVector
OK, rewrite like:
(defn doublets [word1 word2]
(let [n (count word1)
v (vec (cons word1 (filter #(= (count %) n)
(remove #{word1} words))))]
(tree-seq
#(and
(linked-word (% 0) %)
(not= (% 0) word2))
#(vec (cons (linked-word (% 0) (rest %)))
(remove #{(% 0)} (rest %)))
v)))
new error: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
And there is the clue we needed!
We are evaluating things as symbols, not strings! The problem is read-string, which is how you read source code, not data like strings. Delete read-string:
(def words (-> "words.edn"
(io/resource)
(slurp)))
We now get a new error on this line:
v (vec (cons word1 (filter #(= (count %) n)
(remove #{word1} words))))]
ERROR in (dotest-line-40) (RT.java:664)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.UnsupportedOperationException:
count not supported on this type: Character
So your seq has created something like "foo" => [\f \o \o], and you then try to say (count \f). You can't count a single char, only a string.
I'll let you debug it from there.
I'm trying to handle following DSL:
(simple-query
(is :category "car/audi/80")
(is :price 15000))
that went quite smooth, so I added one more thing - options passed to the query:
(simple-query {:page 1 :limit 100}
(is :category "car/audi/80")
(is :price 15000))
and now I have a problem how to handle this case in most civilized way. as you can see simple-query may get hash-map as a first element (followed by long list of criteria) or may have no hash-mapped options at all. moreover, I would like to have defaults as a default set of options in case when some (or all) of them are not provided explicite in query.
this is what I figured out:
(def ^{:dynamic true} *defaults* {:page 1
:limit 50})
(defn simple-query [& body]
(let [opts (first body)
[params criteria] (if (map? opts)
[(merge *defaults* opts) (rest body)]
[*defaults* body])]
(execute-query params criteria)))
I feel it's kind of messy. any idea how to simplify this construction?
To solve this problem in my own code, I have a handy function I'd like you to meet... take-when.
user> (defn take-when [pred [x & more :as fail]]
(if (pred x) [x more] [nil fail]))
#'user/take-when
user> (take-when map? [{:foo :bar} 1 2 3])
[{:foo :bar} (1 2 3)]
user> (take-when map? [1 2 3])
[nil [1 2 3]]
So we can use this to implement a parser for your optional map first argument...
user> (defn maybe-first-map [& args]
(let [defaults {:foo :bar}
[maybe-map args] (take-when map? args)
options (merge defaults maybe-map)]
... ;; do work
))
So as far as I'm concerned, your proposed solution is more or less spot on, I would just clean it up by factoring out parser for grabbing the options map (here into my take-when helper) and by factoring out the merging of defaults into its own binding statement.
As a general matter, using a dynamic var for storing configurations is an antipattern due to potential missbehavior when evaluated lazily.
What about something like this?
(defn simple-query
[& body]
(if (map? (first body))
(execute-query (merge *defaults* (first body)) (rest body))
(execute-query *defaults* body)))
SQL offers a function called coalesce(a, b, c, ...) that returns null if all of its arguments are null, otherwise it returns the first non-null argument.
How would you go about writing something like this in Clojure?
It will be called like this: (coalesce f1 f2 f3 ...) where the fi are forms that should only be evaluated if required. If f1 is non-nil, then f2 should not be evaluated -- it may have side-effects.
Maybe Clojure already offers such a function (or macro).
EDIT: Here a solution that I came up with (modified from Stuart Halloway's Programming Clojure, (and ...) macro on page 206):
(defmacro coalesce
([] nil)
([x] x)
([x & rest] `(let [c# ~x] (if c# c# (coalesce ~#rest)))))
Seems to work.
(defmacro coalesce
([] nil)
([x] x)
([x & rest] `(let [c# ~x] (if (not (nil? c#)) c# (coalesce ~#rest)))))
Fixed.
What you want is the "or" macro.
Evaluates exprs one at a time, from left to right. If a form
returns a logical true value, or returns that value and doesn't
evaluate any of the other expressions, otherwise it returns the
value of the last expression. (or) returns nil.
http://clojuredocs.org/clojure_core/clojure.core/or
If you only want nil and not false do a rewrite of and and name it coalesce.
Edit:
This could not be done as a function because functions evaluate all their arguments first. This could be done in Haskell because functions are lazy (not 100% sure about the Haskell thing).
Based on nickik's answer and "or" clojure macro:
(defmacro coalesce
([] nil)
([x] x)
([x & next]
`(let [v# ~x]
(if (not (nil? v#)) v# (coalesce ~#next)))))
You could use keep introduced in 1.2:
EDIT: extended answer a little bit. Macro for direct invokations. Helper for eg. apply + lazy seq producing the values.
(defn coalesce*
[values]
(first (keep identity values)))
(defmacro coalesce
[& values]
`(coalesce* (lazy-list ~#values)))
However to prevent evaluation of the values one needs some home-grown way.
Ugly:
(lazy-cat [e1] [e2] [e3])
A little more involved but prettier in the code:
(defn lazy-list*
[& delayed-values]
(when-let [delayed-values (seq delayed-values)]
(reify
clojure.lang.ISeq
(first [this] #(first delayed-values))
(next [this] (lazy-list* (next delayed-values)))
(more [this] (or (next this) ())))))
(defmacro lazy-list
[& values]
`(lazy-list* ~#(map (fn [v] `(delay ~v)) values))
Some function versions of coalesce, if you'd rather avoid macros:
(defn coalesce
"Returns first non-nil argument."
[& args]
(first (keep identity args)))
(defn coalesce-with
"Returns first argument which passes f."
[f & args]
(first (filter f args)))
Usage:
=> (coalesce nil "a" "b")
"a"
=> (coalesce-with not-empty nil "" "123")
"123"
Unlike the spec, this will evaluate all args. Use or or another appropriate macro solution if you want short circuiting evaluation.
Perhaps I'm misapprehending the question, but isn't this just the first filtered element?
E.g.:
user=> (first (filter (complement nil?) [nil false :foo]))
false
user=> (first (filter (complement nil?) [nil :foo]))
:foo
user=> (first (filter (complement nil?) []))
nil
user=> (first (filter (complement nil?) nil))
nil
It could be shortened up to:
(defn coalesce [& vals]
(first (filter (complement nil?) vals)))
user=> (coalesce nil false :foo)
false
user=> (coalesce nil :foo)
:foo
user=> (coalesce nil)
nil
user=> (coalesce)
nil