In Clojure, is there a more elegant way of finding the fully qualified name of a function (known to have meta info) than
(defn fully-qualified-name [fn]
(let [fn-meta (meta fn )
fn-ns (ns-name (:ns fn-meta))
]
(str fn-ns "/" (:name fn-meta))))
A run-time solution is required. Read-time and compile-time solutions are welcome.
(resolve 'foo) returns the Var named "foo", with its fully-qualified name.
how about syntax-quoting ? it does auto-qualification. use ` instead of '
user=> `(inc)
(clojure.core/inc)
user=> `(fn)
(clojure.core/fn)
type gives a fully qualified name, regardless of meta info.
The output of .toString could get you started:
user=> (.toString map)
"clojure.core$map#11af7bb"
Related
I have gotten JSON info from an open API using
(def station-info (clj-http.client/get statinfo {:as :json}))
I have spit that information into a .clj file defined as si. It's content look like this:
{:stations [{:station_id "1755", :name "Aker Brygge", :address "Aker Brygge",
:lat 59.91118372188379, :lon 10.730034556850455, :capacity 33}
{:station_id "1101", :name "Stortingstunellen", :address "RÃ¥dhusgata 34",
:lat 59.91065301806209, :lon 10.737365277561025, :capacity 24}]}
When I call the function (map :station_id (:stations si)) it returns an empty list "()".
But if I define a function with the same info in the REPL and then use the same function, it works!
Very strange.
EDIT: Fixed it by turning the string from the file into a data structure:
(def si-data-structure (edn/read-string (slurp si)))
Your function is right, so your data must be wrong. In particular, you will surely find that (:stations si) is also empty. Look at the si variable and see if it really contains what you expect: is it a map? Is :stations one of its keys?
I Fixed it by turning the string from the file into a data structure:
(def si-data-structure (edn/read-string (slurp si)))
I am trying to achieve the following javascript code in clojurescript:
const a = {
"foo": "bar",
//...
};
let b = {
...a,
//^ what is the clojurescript equivalent for this?
"newprop": 10,
};
I have tried to assoc-in, thinking it would behave like a clojure map, with no success...
To provide you with another option, you can use goog.object to interact with JavaScript objects in ClojureScript. The following code will work:
(require 'goog.object)
(def a #js {:foo "bar"})
;; Modify `a` inline
(goog.object/set a "newprop" 10) ;; In JS, this is equivalent to a.newprop = 10
If you want to do a shallow copy of a and modify that value, you can use clone (which will behave like the spread operator).
;; Shallow copy a
(def b (goog.object/clone a))
;; Modify the cloned object
(goog.object/set b "newprop" 10)
There's a neat library you can use though to interact with JavaScript objects if you need to do it often: https://github.com/binaryage/cljs-oops
My question was not clear enough, I had an object defaultProps coming from an external js library. My goal was to create a new instance of this js object and extending it with new props, and feeding it back to a js function expecting a js object. There was more to it than I first foresaw. I finally managed to do it with some juggling with js->clj and clj->js:
(def b
(clj->js (assoc (js->clj a) "newprop" 10)))
Thank you for your answers!
(def a {:foo "bar"})
(def b (assoc a :newProp 10))
This is really just combining two maps together. That can be done with merge:
(def a {"foo" "bar"}) ; Emulating the constant
(def b {"newprop" 10})
(def c (merge a b)) ; {"foo" "bar", "newprop" 10}
I am a newbie and making some exercises. How can I put a def with a list of sentences and a randomizer function inside a defn function? How does that work?
(def list["test1", "test2", "test3"]) - works fine
(rand-nth list) - works fine
How do I put it inside a function defn?
Thanks for help.
IIUC you just want to reimplement rand-nth, no?
(defn wrapped-rand-nth [a-list]
(rand-nth a-list))
If you want the list to be static (non-changing)
(defn randomize []
(rand-nth ["test1" "test2" "test3"]))
works, but it creates the vector upon each call, a better way is to
(let [the-list ["test1" "test2" "test3"]]
(defn randomize []
(rand-nth the-list)))
I'm new to Clojure and playing with it for fun.
I'm reading a CSV file and want to apply a different function to each column. What is an elegant (both concise and readable) way to do this?
I have explored two approaches:
Working on a vector of rows:
for each row...
(def row-1 ["John", "24"])
...I want to apply a different function to each element, and obtain this result:
["John", 24]
The function I want to use are:
(def converters-1 [identity, read-string])
Is there a simple way to apply the converters-1 functions to the row-1 elements?
Working on a map:
With this method I start by turning each row into a map:
(def row-2 {:name "John", :age "24"})
Edit: And I want to obtain this map:
{:name "John", :age 24}
The converters are also stored in a map:
(def converters-2 {:name identity, :age read-string})
Is there a simple way to apply the right converters to the row-2 elements?
I will be interested to read solutions for both approaches.
In the end I will put the data into a map. I'm just not sure whether I want to do the conversions before or after getting this map.
Use map for sequences; use merge-with for maps.
user=> (map #(% %2) converters-1 row-1)
("John" 24)
user=> (merge-with #(% %2) converters-2 row-2)
{:name "John", :age 24}
(map #(%1 %2) converters-1 row-1)
;; ("John" 24)
if (def row-2 {:name "John", :age "24"}) (it's an integer in your example)
(for [x (keys converters-2)] ((converters-2 x) (row-2 x)))
;; ("John" 24)
I found a solution for the map approach, but it's less elegant than Diego's solution with vectors.
(into {} (map (fn [[k v]]
[k ((converters-2 k) v)]
) row-2))
Is there a simpler solutions for this map-approach?
Am I missing a core function that would simplify it?
Edit: reading Diego's edit, I could also use keys:
(into {} (map #(
[% ((converters-2 %) (row-2 %))] ; the key, and the converted value
) (keys row-2)))
But I prefer the previous solution, because it does not need the comment: it is obvious what happens to the key, and to the value. Plus, in this solution I only need to write row-2 once.
Edit 2: If I write (converters-2 k identity), then I only need to indicate the columns who need a transformation. For the other columns (like :name here) identity is the default converter. That is an advantage, compared to the vector approach.
Edit 3: I found a another solution for the map approach, using update-in:
(reduce #(update-in %1 [%2] (converters-2 %2)) row-2 (keys row-2))
Well, now that it's written, to my novice eyes it's harder to read and understand.
So far the vector solution is still best. I'll keep my eyes open for a better map solution; it might come in handy some day.
Say I have defined a macro for CL-WHO:
(defmacro test-html (&body body)
`(with-html-output-to-string (*standard-output* nil :PROLOGUE t :indent t)
(:html
(:body
,#body))))
Then:
(test-html (:h1 "hallo"))
Gives (first line removed):
"<html>
<body>
<h1>
hallo
</h1>
</body>
</html>"
As expected. Now I have defined a function to generate the s-expression to be used by CL-WHO:
(defun test-header (txt)
`(:h1 ,txt))
When called with "hallo" returns
(:h1 "hallo")
BUT now when I call
(test-html (test-header "hallo"))
It returns:
"<html>
<body>
</body>
</html>"
What went wrong and why?
The way I tend to solve this problem is by defining a shortcut macro like
(defmacro html-to-stout (&body body)
"Outputs HTML to standard out."
`(with-html-output (*standard-output* nil :indent t) ,#body))
or the string-equivalent. The key here is that it doesn't output a :prologue, so it can output an HTML chunklet rather than a full page. Once you've got that, you can do things like
(defun test-header (text)
(html-to-stout
(:h1 (str text))))
(test-html (test-header "Hello Hello"))
I had the same problem. As far as I could google out was, that it is not possible in the official version of cl-who: http://lisp-univ-etc.blogspot.com/2009/03/cl-who-macros.html
I used this version instead, which supports macros: https://github.com/vseloved/cl-who