I'm writing an interface layer with pure functions in ClojureScript, but I'm getting undesired results after compile. Simple parameterized functions work fine. The example:
(defn rev [s]
(.. s (split "") (reverse) (join "")))
... will successfully generate function rev(s){return s.split("").reverse().join(""); }, while, with more complex parameters, like [s a & [b]], or with parametric polimorphism, it generates an anonymous function:
(defn substr
([s a b]
(.. s (substr a b)))
([s a]
(.. s (substr a))))
... generates: function (s,a,b){ switch(arguments.length){ case 2: return substr__2.call(this,s,a); case 3: return substr__3.call(this,s,a,b); } throw(new Error('Invalid arity: ' + arguments.length)); }.
It doesn't even work with (def substr (fn ... instead. How can I force a function to be named with defn?
Use ^:export on your function if you are going to be calling it from javascript.
(defn ^:export substr
([s a b]
(.. s (substr a b)))
([s a]
(.. s (substr a))))
The compiler should then generate the name so that you can call it from javascript.
I did it by exporting the function to the Window global object, of JavaScript:
(aset js/window "substr" stdlib.string/substr)
Related
As a minimal example of what I want to do:
(defn mkfn [func]
(fn func [a] (print "I am a function")))
(mkfn 'x) ; => #function[user/mkfn/func--10871]
(type x)
(x)
The last two both result in:
Syntax error compiling at (conjure-log-12628.cljc:1:1).
Unable to resolve symbol: x in this context
I'm not sure why this doesn't work since fn takes symbols as input and 'x is a symbol. I'm also not sure how to accomplish this task.
For that matter:
user=> (def (eval 'y) 3)
Syntax error compiling def at (conjure-log-12628.cljc:1:1).
user=> (def 'y 3)
Syntax error compiling def at (conjure-log-12628.cljc:1:1).
First argument to def must be a Symbol
First argument to def must be a Symbol
user=> (type 'y)
clojure.lang.Symbol
Other things that don't work:
(defn mkfn [func]
(fn (sympol func) [a] (print "i am a function")))
(symbol "y") ; => y ; a symbol
(def (symbol "y") 3) ; => an err
You will probably need a macro. It seems that you want to call that function by the provided name, so you also have to replace fn with defn.
And you have to be careful about a number of arguments, because function x with argument vector [a] must be called with one argument, and not like (x).
(defmacro mkfn [func]
`(defn ~func [~'a]
(print "I am a function")))
(mkfn x)
=> #'user/x
(x 1)
I am a function=> nil
There is also other way, using intern, so you can completely avoid writing macros:
(intern *ns* 'x (fn [a] (print "I am a function")))
=> #object...
(x 1)
I am a function=> nil
Example with intern:
(defn mkfn [func]
(intern *ns* func (fn [a] (print "I am a function"))))
=> #'user/mkfn
(mkfn 'y)
=> #'user/y
(y 1)
I am a function=> nil
As for your errors, def is a special form, so it has different evaluation rules. It doesn't evaluate the first argument, which has to be a symbol- and (unevaluated) (eval 'y), 'y or (symbol "y") aren't symbols, while y is.
You gonna need a macro for that since you need code writing code.
(defmacro mkfn [func]
`(fn ~func [~'a] ...))
There 2 ways of doing it, either function plus eval or macro. If you really want to programatically create a new function with your chosen name, the macro solution is the way to go.
The function + eval solution is instructive, but you'll have to either quote the function name when you call it (via a 2nd eval) or save the created function in another variable when you create it.
If you are interested in writing macros, please see this other question first: How do I write a Clojure threading macro?
For the function + eval, we can start with my favorite template project and add the following:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn maker-eval
[fn-sym]
(let [ll (list 'fn 'anon-fn [] (str "I am " fn-sym))]
(spyx :eval ll)
(eval ll)))
(verify
(let [anon-fn-1 (maker-eval 'aaa)]
(is= "I am aaa" (anon-fn-1))) ; need the temp local variable
(let [anon-fn-2 (maker-eval 'bbb)]
(is= "I am bbb" (anon-fn-2))) ; need the temp local variable
)
and we can see the creation and use of the function, along with printed output:
:eval ll => (fn anon-fn [] "I am aaa")
:eval ll => (fn anon-fn [] "I am bbb")
For the macro version, we type
(defn maker-macro-impl
[fn-sym]
(let [ll `(defn ~fn-sym [] (str "I am " (str (quote ~fn-sym))))]
(spyx :macro ll)
ll))
(defmacro maker-macro
[fn-sym] (maker-macro-impl fn-sym))
(verify
(let [anon-fn-3 (maker-macro-impl 'ccc)]
(is= anon-fn-3 (quote
(clojure.core/defn ccc [] (clojure.core/str "I am " (clojure.core/str (quote ccc)))))))
(maker-macro ddd)
(is= (ddd) "I am ddd"))
and see printed:
:macro ll => (clojure.core/defn ccc [] (clojure.core/str "I am " (clojure.core/str (quote ccc))))
Note that the local variable anon-fn-3 was only used to test the maker-macro-impl function, but was not needed to call the newly-created function ddd
at the end of the unit test.
Which form is better?
(defn my-func [arg arg2]
(fn [] [:div (str arg arg2)]))
Or this one?
(defn my-func []
(fn [arg arg2] [:div (str arg arg2)]))
I'm writting from my phone so forgive me indentation...
There's other difference between these functions aside from arity.
The first function will close over arg, and arg2 on first render, and use these arguments for each subsequent rerender. E.g.
(def a 1)
(def b 2)
[my-func a b]
will always result in [:div '12'] whether or not a or b were changed
The second function will take arg, and arg2 on each render and will update the result when arguments change.
Look for Rookie mistake in reagent docs
I believe your question should be which one is correct(The first one is correct). The second one has got an arity exception. Based on your use case, I would prefer to define and call the anonymous function so as to get the results. Consider this number one edit:
(defn my-func [arg arg2]
((fn [] [:div (str arg arg2)])))
I want to write a macro, sym-def, which has the same behavior as the special form def but uses (symbol "c"), say, as the first argument.
My first step was
(def (symbol "c") 4)
but this returned the error First argument to def must be a Symbol.
My second step was
(eval `(def ~(symbol "c") 4))
and this succeeded in defining c to be 4 in the global environment.
Why did my first step fail while the second step succeeded?
Finally, I attempted to write the desired macro
(defmacro sym-def [sym value] `(def ~sym ~value))
but this has a "bad" macroexpand
(macroexpand '(sym-def (symbol "c") 4)) => (def (symbol "c") 4)
so that
(sym-def (symbol "c") 4)
fails with the same error as my first step.
What is the correct way to write the macro?
def does not evaluate its first argument. Imagine the chaos if it did! You couldn't write
(def x 1)
because it would first try to evaluate x, and fail because x is not yet defined! Now, since it doesn't evaluate its arguments, clearly it makes sense that
(def (symbol "c") 4)
doesn't work, just as
(def 'c 4)
wouldn't. def requires its first argument to be a literal symbol. You don't have a literal symbol, so you can't use def.
But there is a lower-level mechanism to interact with the mappings in a namespace. In this case, you want clojure.core/intern:
(intern *ns* (symbol "c") 4)
intern is an ordinary function, so it evaluates all its arguments, meaning you can construct your var name in whatever crazy way you want. Then it adds to the given namespace a var mapping your symbol to its desired value.
A correct form for the macro you want to write is the following:
(defmacro sym-def [s v] `(def ~(eval s) ~v))
... or equivalently:
(defmacro sym-def [s v] (list `def (eval s) v))
You just need to evaluate the first argument inside the macro, because a macro's arguments are not evaluated when it is applied. If the only symbol-producing expressions you are going to use are calls to symbol, you may prefer the following macro:
(defmacro defsym [s v] (list `def (symbol s) v))
... and a companion to it:
(defmacro sym [s] (symbol s))
These macros translate a string or symbol to a symbol. Here are some examples of their use:
(defsym "the first natural number" 0)
;=> #'user/the first natural number
(sym "the first natural number")
;=> 0
(defsym pi 3.14159) ;same as: (def pi 3.14159)
;=> #'user/pi
(sym pi) ;same as: pi
;=> 3.14159
The variations given below might also be usefull:
(defmacro defsym* [s v] (list `def (symbol (eval s)) v))
(defmacro sym* [s] (symbol (eval s)))
They translate a string/symbol-producing expression to a symbol after evaluating it. Here are some examples of defsym*'s use:
(defsym* "abc" "xyz")
(defsym* (str \a \b \c) "xyz")
(defsym* (symbol "abc") "xyz")
(defsym* 'abc "xyz")
;all the previous are equivalent and what follows is valid for any of them
;=> #'user/abc
abc
;=> "xyz"
(defsym* abc 0)
;=> #'user/xyz
abc
;=> "xyz"
xyz
;=> 0
Suppose I have the following clojure function call:
(def mymap {:a1 1 :a2 2})
(defn my-adder [input-map]
(let [a1 (:a1 input-map)
a2 (:a2 input-map)]
(+ a1 a2)))
(my-adder mymap)
What I'm looking for is for some way to make the my-adder function simpler by converting the map to params automatically - something like:
(defn my-adder [(magic-function input-map)]
(+ a1 a2))
Can someone point me to what I'm missing?
What I think you're looking for is destructuring. Here's what you can do:
(def mymap {:a1 1 :a2 2})
(defn my-adder [{:keys [a1 a2]}]
(+ a1 a2))
(my-adder mymap)
You can learn more about it here.
Use can use like bellow. It's called as Clojure: Destructuring. You can find more here
(defn my-adder [{a1 :a1 a2 :a2}]
(+ a1 a2))
In addition to the answers showing destructuring, you could also use apply and vals if simply adding all values from your map together is fine for you:
(defn my-adder [m]
(apply + (vals m)))
Or you can use the fnk function in the plumbing libary
(use 'plumbing.core)
(defnk my-adder [a b]
(+ a b))
I'd like to do this (in REPL or anywhere)
(defn (symbol "print-string") [k] (println k))
and then be able to do
(print-string "lol")
Or, if there is any other way to create defn from custom strings in macroses, could you push me into the right direction please?
(defmacro defn-with-str [string args & body]
`(defn ~(symbol string) ~args ~#body))
(defn-with-str "print-string" [k] (println k))
(print-string "lol")
dnolen's solution works at macro expansion time, Brian Carper's at read-time. Now, here's one for run-time:
(intern *ns* (symbol "a") (fn [k] (println k)))
I like dnolen's answer better, but you can do this too:
(defn #=(symbol "print-string") [k] (println k))
#=() is evaluated at read-time. I don't know how stable a feature of Clojure this is, I wouldn't rely on it not to change in the future. Macros are how I'd do it.
FYI - dnolen's answer will only work for literal strings, and not for strings in def'd or let'd variables.
(defmacro defn-with-str [string args & body]
`(defn ~(symbol string) ~args ~#body))
(def hisym "hi")
(defn-with-str hisym [] (println "hi"))
You now have a function called "hisym"
(hi) -> java.lang.Exception: Unable to resolve symbol: hi in this context (NO_SOURCE_FILE:6)
(hisym) -> prints "hi"
To avoid this, eval the function name string in the macro
(defmacro defn-with-str [string args & body]
`(defn ~(symbol (eval string)) ~args ~#body))