(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
Related
For the most part I understand what Clojure is telling me with it's error messages. But I am still clueless as to find out where the error happened.
Here is an example of what I mean
(defn extract [m]
(keys m))
(defn multiple [xs]
(map #(* 2 %) xs))
(defn process [xs]
(-> xs
(multiple) ; seq -> seq
(extract))) ; map -> seq ... fails
(process [1 2 3])
Statically typed languages would now tell me that I tried to pass a sequence to a function that expects a map on line X. And Clojure does this in a way:
ClassCastException java.lang.Long cannot be cast to java.util.Map$Entry
But I still have no idea where the error happened. Obviously for this instance it's easy because there are just 3 functions involved, you can easily just read through all of them but as programs grow bigger this gets old very quickly.
Is there a way find out where the errors happened other than just proof reading the code from top to bottom? (which is my current approach)
You can use clojure.spec. It is still in alpha, and there's still a bunch of tooling support coming (hopefully), but instrumenting functions works well.
(ns foo.core
(:require
;; For clojure 1.9.0-alpha16 and higher, it is called spec.alpha
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))
;; Extract takes a map and returns a seq
(s/fdef extract
:args (s/cat :m map?)
:ret seq?)
(defn extract [m]
(keys m))
;; multiple takes a coll of numbers and returns a coll of numbers
(s/fdef multiple
:args (s/cat :xs (s/coll-of number?))
:ret (s/coll-of number?))
(defn multiple [xs]
(map #(* 2 %) xs))
(defn process [xs]
(-> xs
(multiple) ; seq -> seq
(extract))) ; map -> seq ... fails
;; This needs to come after the definition of the specs,
;; but before the call to process.
;; This is something I imagine can be handled automatically
;; by tooling at some point.
(stest/instrument)
;; The println is to force evaluation.
;; If not it wouldn't run because it's lazy and
;; not used for anything.
(println (process [1 2 3]))
Running this file prints (among other info):
Call to #'foo.core/extract did not conform to spec: In: [0] val: (2
4 6) fails at: [:args :m] predicate: map? :clojure.spec.alpha/spec
#object[clojure.spec.alpha$regex_spec_impl$reify__1200 0x2b935f0d
"clojure.spec.alpha$regex_spec_impl$reify__1200#2b935f0d"]
:clojure.spec.alpha/value ((2 4 6)) :clojure.spec.alpha/args ((2 4
6)) :clojure.spec.alpha/failure :instrument
:clojure.spec.test.alpha/caller {:file "core.clj", :line 29,
:var-scope foo.core/process}
Which can be read as: A call to exctract failed because the value passed in (2 4 6) failed the predicate map?. That call happened in the file "core.clj" at line 29.
A caveat that trips people up is that instrument only checks function arguments and not return values. This is a (strange if you ask me) design decision from Rich Hickey. There's a library for that, though.
If you have a REPL session you can print a stack trace:
(clojure.stacktrace/print-stack-trace *e 30)
See http://puredanger.github.io/tech.puredanger.com/2010/02/17/clojure-stack-trace-repl/ for various different ways of printing the stack trace. You will need to have a dependency such as this in your project.clj:
[org.clojure/tools.namespace "0.2.11"]
I didn't get a stack trace using the above method, however just typing *e at the REPL will give you all the available information about the error, which to be honest didn't seem very helpful.
For the rare cases where the stack trace is not helpful I usually debug using a call to a function that returns the single argument it is given, yet has the side effect of printing that argument. I happen to call this function probe. In your case it can be put at multiple places in the threading macro.
Re-typing your example I have:
(defn extract [m]
(keys m))
(defn multiply [xs]
(mapv #(* 2 %) xs))
(defn process [xs]
(-> xs
(multiply) ; seq -> seq
(extract))) ; map -> seq ... fails ***line 21***
(println (process [1 2 3]))
;=> java.lang.ClassCastException: java.lang.Long cannot be cast
to java.util.Map$Entry, compiling:(tst/clj/core.clj:21:21)
So we get a good clue in the exception where is says the file and line/col number tst.clj.core.clj:21:21 that the extract method is the problem.
Another indispensible tool I use is Plumatic Schema to inject "gradual" type checking into clojure. The code becomes:
(ns tst.clj.core
(:use clj.core tupelo.test)
(:require
[tupelo.core :as t]
[tupelo.schema :as tsk]
[schema.core :as s]))
(t/refer-tupelo)
(t/print-versions)
(s/defn extract :- [s/Any]
[m :- tsk/Map]
(keys m))
(s/defn multiply :- [s/Num]
[xs :- [s/Num]]
(mapv #(* 2 %) xs))
(s/defn process :- s/Any
[xs :- [s/Num]]
(-> xs
(multiply) ; seq -> seq
(extract))) ; map -> seq ... fails
(println (process [1 2 3]))
clojure.lang.ExceptionInfo: Input to extract does not match schema:
[(named (not (map? [2 4 6])) m)] {:type :schema.core/error, :schema [#schema.core.One{:schema {Any Any},
:optional? false, :name m}],
:value [[2 4 6]], :error [(named (not (map? [2 4 6])) m)]},
compiling:(tst/clj/core.clj:23:17)
So, while the format of the error message is a bit lengthy, it tells right away that we passed a parameter of the wrong type and/or shape into the method extract.
Note that you need a line like this:
(s/set-fn-validation! true) ; enforce fn schemas
I create a special file test/tst/clj/_bootstrap.clj so it is always in the same place.
For more information on Plumatic Schema please see:
https://github.com/plumatic/schema
https://youtu.be/o_jtwIs2Ot8
https://github.com/plumatic/schema/wiki/Basics-Examples
https://github.com/plumatic/schema/wiki/Defining-New-Schema-Types-1.0
I wrote a specialized function construct, which under the hood is really just a Clojure function. So basically I have a function that makes (similar to fn) and a function that calls my specialized functions (similar to CL's funcall).
My constructor assigns metadata (at compile-time) so I could distinguish between "my" functions and other/normal Clojure functions.
What I want to do is to make a macro that lets users write code as if my functions were normal functions. It would do so by walking over the code, and in functions calls, when the callee is a specialized function, it would change the call so it would use my caller (and also inject some extra information). For example:
(defmacro my-fn [args-vector & body] ...)
(defmacro my-funcall [myfn & args] ...)
(defmacro with-my-fns [& body] ...)
(with-my-fns
123
(first [1 2 3])
((my-fn [x y] (+ x y))) 10 20)
; should yield:
(do
123
(first [1 2 3])
(my-funcall (my-fn [x y] (+ x y)) 10 20))
I run into problems in lexical environments. For example:
(with-my-fns
(let [myf (my-fn [x y] (+ x y))]
(myf))
In this case, when the macro I want to write (i.e. with-my-fns) encounters (myf), it sees myf as a symbol, and I don't have access to the metadata. It's also not a Var so I can't resolve it.
I care to know because otherwise I'll have to put checks on almost every single function call at runtime. Note that I don't really care if my metadata on the values are actual Clojure metadata; if it's possible with the type-system and whatnot it's just as good.
P.S. I initially wanted to just ask about lexical environments, but maybe there are more pitfalls I should be aware of where my approach would fail? (or maybe even the above is actually an XY problem? I'd welcome suggestions).
As #OlegTheCat already pointed out in the comment section, the idea to use meta-data does not work.
However I might have a solution you can live with:
(ns cl-myfn.core)
(defprotocol MyCallable
(call [this magic args]))
(extend-protocol MyCallable
;; a clojure function implements IFn
;; we use this knowledge to simply call it
;; and ignore the magic
clojure.lang.IFn
(call [this _magic args]
(apply this args)))
(deftype MyFun [myFun]
MyCallable
;; this is our magic type
;; for now it only adds the magic as first argument
;; you may add all the checks here
(call [this magic args]
(apply (.myFun this) magic args)))
;;turn this into a macro if you want more syntactic sugar
(defn make-myfun [fun]
(MyFun. fun))
(defmacro with-myfuns [magic & funs]
`(do ~#(map (fn [f#]
;; if f# is a sequence it is treated as a function call
(if (seq? f#)
(let [[fun# & args#] f#]
`(call ~fun# ~magic [~#args#]))
;; if f# is nonsequential it is left alone
f#))
funs)))
(let [my-prn (make-myfun prn)]
(with-myfuns :a-kind-of-magic
123
[1 2 3]
(prn :hello)
(my-prn 123)))
;; for your convenience: the macro-expansion
(let [my-prn (make-myfun prn)]
(prn (macroexpand-1 '(with-myfuns :a-kind-of-magic
123
[1 2 3]
(prn :hello)
(my-prn 123)))))
the output:
:hello
:a-kind-of-magic 123
(do 123 [1 2 3] (cl-myfn.core/call prn :a-kind-of-magic [:hello]) (cl-myfn.core/call my-prn :a-kind-of-magic [123]))
I have a question regarding how to define functions/macros which call other macros or special forms but where one of the symbols passed in needs to be dynamic.
The simplest version of this question is described below:
We can define variables using def
(def x 0)
But what if we wanted the name x to be determined programmatically so that we could do the equivalent of?
(let [a 'b]
(our-def a 3)) => user/b
We could try to define a function
(defn defn2 [sym val]
(def sym val))
However it does not do what we want
(def2 'y 1) => #'user/sym
At first it seems like a macro works (even though it seems like it would be unnecessary)
(defmacro def3 [sym val]
`(def ~sym ~val))
(def3 z 2) => user/z
but it is just superficial, because we're really right back where we started with regular def.
(let [a 'b]
(def3 a 3)) => user/a
I can do it if I use eval, but it doesn't seem like eval should be necessary
(defn def4 [sym val]
(eval `(def ~sym ~val)))
(let [a 'b]
(def4 a 4)) => user/b
If there are other built-in commands that could achieve this particular example, they are not really what I am looking for since def is just to show a particular example. There are macros more complicated than def that I might want to call and not have to worry about how they were internally implemented.
First: The right way to do this is to use macro that starts with def... since this is the way people have been doing defs and is of little surprise to the user.
To answer you question: Use intern:
(def foo 'bar)
(intern *ns* foo :hi)
(pr bar) ;; => :hi
(intern *ns* foo :hi2)
(pr bar) ;; => :hi2
If you want to use macros do this:
(def z 'aa)
(defmacro def3 [sym val]
`(def ~(eval sym) ~val))
(def3 z 2)
(pr aa) ;; => 2
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))))))
Why don't when-let and if-let support multiple bindings by default?
So:
(when-let [a ...
b ...]
(+ a b))
...instead of:
(when-let [a ...
(when-let [b ...
(+ a b)))
I am aware that I can write my own macro or use a monad (as described here: http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html).
Because (for if-let, at least) it's not obvious what to do with the "else" cases.
At least, motivated by Better way to nest if-let in clojure I started to write a macro that did this. Given
(if-let* [a ...
b ...]
action
other)
it would generate
(if-let [a ...]
(if-let [b ...]
action
?))
and it wasn't clear to me how to continue (there are two places for "else").
You can say that there should be a single alternative for any failure, or none for when-let, but if any of the tests mutate state then things are still going to get messy.
In short, it's a little more complicated than I expected, and so I guess the current approach avoids having to make a call on what the solution should be.
Another way of saying the same thing: you're assuming if-let should nest like let. A better model might be cond, which isn't a "nested if" but more an "alternative if", and so doesn't fit well with scopes... or, yet another way of saying it: if doesn't handle this case any better.
Here is when-let*:
(defmacro when-let*
"Multiple binding version of when-let"
[bindings & body]
(if (seq bindings)
`(when-let [~(first bindings) ~(second bindings)]
(when-let* ~(vec (drop 2 bindings)) ~#body))
`(do ~#body)))
Usage:
user=> (when-let* [a 1 b 2 c 3]
(println "yeah!")
a)
;;=>yeah!
;;=>1
user=> (when-let* [a 1 b nil c 3]
(println "damn! b is nil")
a)
;;=>nil
Here is if-let*:
(defmacro if-let*
"Multiple binding version of if-let"
([bindings then]
`(if-let* ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
`(if-let [~(first bindings) ~(second bindings)]
(if-let* ~(vec (drop 2 bindings)) ~then ~else)
~else)
then)))
Usage:
user=> (if-let* [a 1
b 2
c (+ a b)]
c
:some-val)
;;=> 3
user=> (if-let* [a 1 b "Damn!" c nil]
a
:some-val)
;;=> :some-val
EDIT: It turned out bindings should not be leaked in the else form.
If you use cats, then there is a mlet function that you might find useful :
(use 'cats.builtin)
(require '[cats.core :as m])
(require '[cats.monad.maybe :as maybe])
(m/mlet [x (maybe/just 42)
y nil]
(m/return (+ x y)))
;; => nil
As you can see, the mlet short-circuits when encountering a nil value.
(from section 6.5.1 nil)