Get string name of passed in var in clojure? - clojure

How do I get the string name of a 2nd nested var like so?
(def bar "abc")
(defn string-var [foo]
(...))
(= "bar" (string-var bar))

You can do this with macro
(def bar "abc")
(defmacro string-var [foo]
(name foo))
(string-var bar)
=> "bar"

Related

How to get the corresponding var of a function parameter in Clojure?

Consider the following Clojure REPL commands:
user=> (defn foobar [x] (println x))
#'user/foobar
user=> (defn somefun [] )
#'user/somefun
user=> (foobar somefun)
#object[user$somefun 0x4efeab94 user$somefun#4efeab94]
nil
user=> (foobar (var somefun))
#'user/somefun
nil
Question: how can I achieve that foobar prints the var-form of its parameter?
This does not work:
(defn foobar [x] (println (var x)))
Result:
CompilerException java.lang.RuntimeException: Unable to resolve var: x in this context, compiling:(/tmp/form-init882462612882384638.clj:1:27)
It does not work with (defn foobar [x] (println #'x)) either (same result).
how can I achieve that foobar prints the var-form of its parameter?
I'm not sure this is possible using a defn function. Once you're in the body of foobar, x is a function value (not a symbol) and var expects a symbol argument. You can resolve the var before calling the function, or you could use a macro which allows you to work with the function's symbol:
(defmacro print-var [x]
`(println (var ~x)))
(print-var somefun)
;; #'user/somefun

Is it possible to destructure in case for use in a threading macro?

(def val { :type "bar" })
(-> val
(case ???
"bar" "bar type"
"baz" "baz type"
"other type"))
I'd like to include a case in a threading macro so I can branch based on one of the keys of val, a hash map. Is this possible?
EDIT: I need to thread val not a key from val as further functions will need the whole of val. I essentially want to branch to a function within the threading macro based on a key of val. But still pass val onward.
Consider using a multimethod dispatch here:
(defmulti some-operation :type)
(defmethod some-operation "bar"
[val]
(println "Bar type!")
(assoc val :x 42))
(defmethod some-operation "baz"
[val]
(println "Baz type!")
(assoc val :x 100))
(-> {:type "bar"}
some-operation
some-other-operation)
This is something which seems to work and serves as a better example of what I want to do:
(def val { :type "bar" })
(-> val
(do-something-to-val-based-on-type)
(do-something-else-to-val))
(defn do-something-to-val-based-on-type [val]
(let [:type (:type val)]
(case type
"bar" (do-something-to-bar-type-val val)
"baz" (do-something-to-baz-type-val val)
val))) ;; default, no-op
(defn do-something-to-bar-type-val [val]
;; something
val)
(defn do-something-to-baz-type-val [val]
;; something
val)
also, since a threading macro simply adds an item to a seq for every "action", you can easily use anonymous function for that:
user> (def val { :type "bar" })
#'user/val
user> (-> val
((fn [{type :type}]
(case type
"bar" "bar type"
"baz" "baz type"
"other type"))))
;;=> "bar type"
if you wish, you can also make up special macro, rearranging let for usage in ->:
user> (defmacro let-inv [x binding & body]
`(let [~binding ~x] ~#body))
#'user/let-inv
user> (-> val
(let-inv {type :type}
(case type
"bar" "bar type"
"baz" "baz type"
"other type")))
;;=> "bar type"
This is easily accomplished using the it-> threading macro from the Tupelo library:
(ns tst.clj.core
(:use clj.core tupelo.test)
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(def val { :type "bar" })
(println "result => "
(it-> val
(case (grab :type it)
"bar" "bar-type"
"baz" "baz-type"
"other-type")))
to yield the desired result:
result => bar-type
The it-> macro assigns the intermediate value to the symbol it at each stage of the pipeline. In this case we use the grab function to extract the :type value. It works like (:type it) but will throw if the key is not found.
Another example:
(it-> 1
(inc it) ; thread-first or thread-last
(+ it 3) ; thread-first
(/ 10 it) ; thread-last
(str "We need to order " it " items." ) ; middle of 3 arguments
;=> "We need to order 2 items." )

Clojure destructure map using :keys with qualified keywords not working

I've tried this with both 1.7.0 and 1.8.0 and it appears that Clojure does not destructure maps using :keys whose keys are fully qualified. I don't think it has to do with being in the tail on the arguments as it doesn't work when I switch around the function argument positions as well.
(ns foo.sandbox)
(def foo ::foo)
(def bar ::bar)
(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar))
(normalize-vals {} {foo 1 bar 2})
=> normalize-vals {:foo.sandbox/foo 1, :foo.sandbox/bar 2} and foo nil bar nil
However; this works:
(defn normalize-vals
[mmap & [{a foo b bar :as ops}]]
(println "normalize-vals " ops " and foo " a " bar" b))
(normalize-vals {} {foo 1 bar 2})
=> normalize-vals {:cmt.sandbox/foo 1, :cmt.sandbox/bar 2} and foo 1 bar 2
Is this a defect?
Let's take your function as is:
(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar))
Note that foo & bar above are local bindings, they do not refer to anything outside of the function.
...and rewrite the other bits of code a bit:
(def foo-const ::foo)
(def bar-const ::bar)
Don't pay too much attention to the naming here, the point is to use different names.
(normalize-vals {} {foo 1 bar 2})
;; error: ...Unable to resolve symbol: foo in this context...
(normalize-vals {} {foo-const 1 bar-const 2})
;; prints: normalize-vals {:user/foo 1, :user/bar 2} and foo nil bar nil
The lesson should be to use unique names as much as possible.
Why did the 2nd variant work?
In the destructuring form {a foo b bar :as ops};
a & b are new local bindings. If we had a var named a or b these would override them within the scope of this function.
foo & bar are resolved from the environment. If we don't suffix them with -const as above we would get a CompilerException just like the one above.
You are destructuring using unqualified keywords, so instead of:
[mmap & [{:keys [foo bar] :as ops}]]
you should use
[mmap & [{:keys [::foo ::bar] :as ops}]]
You can use clojure.walk/macroexpand-all to expand normalize-vals:
(clojure.walk/macroexpand-all '(defn normalize-vals
[mmap & [{:keys [foo bar] :as ops}]]
(println "normalize-vals " ops " and foo " foo " bar" bar)))
=> (def normalize-vals (fn* ([mmap & p__26720] (let* [vec__26721 p__26720 map__26722 (clojure.core/nth vec__26721 0 nil) map__26722 (if (clojure.core/seq? map__26722) (. clojure.lang.PersistentHashMap create (clojure.core/seq map__26722)) map__26722) ops map__26722 foo (clojure.core/get map__26722 :foo) bar (clojure.core/get map__26722 :bar)] (println "normalize-vals " ops " and foo " foo " bar" bar)))))
The important part of the expansion to note is:
foo (clojure.core/get map__26722 :foo)
bar (clojure.core/get map__26722 :bar)
The keys in the map destructuring are therefore converted to keywords at compile time and the values from the foo and bar vars in the namespace will not be used.

How do you make a callable object in Clojure?

How do you make a callable type or object in Clojure?
For example, how could I define a record Foo taking a single value :bar which could be called to print that value?
user=> (def foo (Foo. "Hello world"))
user=> (foo)
Hello World
user=> (:bar foo)
"Hello World"
(defrecord Foo [bar]
clojure.lang.IFn
(invoke [_] (println bar)))
((Foo. "Hello, world!"))
;; => Hello, world!
(:bar (Foo. "Hello, world!"))
;; => "Hello, world!"
...Whether doing this is a good idea is another question.
Records implementing IFn
(defrecord Foo [bar]
clojure.lang.IFn
(invoke [_] (println bar))
(applyTo [this args] (clojure.lang.AFn/applyToHelper this args)))

How to convert a clojure keyword into a string?

In my application I need to convert clojure keyword eg. :var_name into a string "var_name". Any ideas how that could be done?
user=> (doc name)
-------------------------
clojure.core/name
([x])
Returns the name String of a string, symbol or keyword.
nil
user=> (name :var_name)
"var_name"
Actually, it's just as easy to get the namespace portion of a keyword:
(name :foo/bar) => "bar"
(namespace :foo/bar) => "foo"
Note that namespaces with multiple segments are separated with a '.', not a '/'
(namespace :foo/bar/baz) => throws exception: Invalid token: :foo/bar/baz
(namespace :foo.bar/baz) => "foo.bar"
And this also works with namespace qualified keywords:
;; assuming in the namespace foo.bar
(namespace ::baz) => "foo.bar"
(name ::baz) => "baz"
Note that kotarak's answer won't return the namespace part of keyword, just the name part - so :
(name :foo/bar)
>"bar"
Using his other comment gives what you asked for :
(subs (str :foo/bar) 1)
>"foo/bar"
It's not a tedious task to convert any data type into a string, Here is an example by using str.
(defn ConvertVectorToString []
(let [vector [1 2 3 4]]
(def toString (str vector)))
(println toString)
(println (type toString)
(let [KeyWordExample (keyword 10)]
(def ConvertKeywordToString (str KeyWordExample)))
(println ConvertKeywordToString)
(println (type ConvertKeywordToString))
(ConvertVectorToString) ;;Calling ConvertVectorToString Function
Output will be:
1234
java.lang.string
10
java.lang.string
This will also give you a string from a keyword:
(str (name :baz)) -> "baz"
(str (name ::baz)) -> "baz"