Clojure embed var to String, a alternative way? Like sprintf way? - clojure

(str "I don't know what " (:name a) " eats."))
I know this is the right way to construct a string with variables.
But is there a way similar to this?
(str "I dont know what %s eats." (:name a))
I tried and this is not valid syntax, but is there a similar way in Clojure?
Thanks.

Diego Basch mentioned format, which is a good answer. You can also use cl-format:
(clojure.pprint/cl-format nil "I don't know what ~a eats." "Joe")
With nil as the second argument, this returns a string. Other options for the second argument will cause the string to be written somewhere.
format uses java.lang.String.format. cl-format is a Clojure version of Common Lisp's format. For formatting strings, their functionality is very similar, but there are a few things that cl-format can do well that Clojure's format doesn't. Simple example--printing nil:
(format "I don't know what %s eats." nil)
;=> "I don't know what null eats."
(clojure.pprint/cl-format nil "I don't know what ~a eats." nil)
;=> "I don't know what nil eats."

format is what you want. For example:
(format "I don't know what %s eats." "Joe")
=> "I don't know what Joe eats."

Related

Clojure evaluating string variable as a symbol, is this use of read-string okay?

I can use memfn to create a clojure function that invokes a java function.
(macroexpand '(memfn startsWith prefix))
=> (fn* ([target2780 prefix] (. target2780 (startsWith prefix))))
((memfn startsWith prefix) "abc" "a")
=> true
memfn requires that the function name be a symbol. I'm wondering if I can write a macro to invoke an arbitrary method whose name is provided as a string. That is, I'd like to be able to invoke the following:
(def fn-name "startsWith")
=> #'user/fn-name
(macroexpand '(memfn' fn-name "prefix"))
=> (fn* ([target2780 prefix] (. target2780 (startsWith prefix))))
((memfn fn-name "prefix") "abc" "a")
=> true
The only way I can think to do this involves using read-string.
(defmacro memfn' [fn-name arg-name]
`(memfn ~(read-string fn-name) ~arg-name))
Edit: A version using read-string and eval that actually works the way I want it to.
(defn memfn' [fn-name arg-name]
(eval (read-string (str "(memfn " fn-name " " arg-name ")"))))
Am I missing a fundamental macro building tool to take the string that a symbol references and turn it into a literal without potentially executing code, as read-string might?
Thanks for any ideas!
There's no way to do this, with or without read-string. Your proposed solution doesn't work. The distinction you're really trying to make is not between string and symbol, but between runtime data and compile-time literals. Macros do not evaluate the arguments they receive, so even if fn-name is the name of a var whose value is "startsWith", memfn (or your memfn' macro) will only ever see fn-name.
If you are interested in calling java methods only then you can rely on java.lang.reflect.Method and its invoke method.
Something like this should work for parameterless methods and would not require a macro.
(defn memfn' [m]
(fn [o] (.invoke (.getMethod (-> o .getClass) m nil) o nil)))
((memfn' "length") "clojure")
;=>7

Is there a way to include type hints inside the clojure threading macro?

For example, as in the example here,
=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
=> "X"
I'd like to be able to do something like
=> (-> ^String "a b c " .... etc etc
to avoid the reflection penalties, esp. in interfacing with java code.
It is possible to type hint expressions using the -> macro. While the following uses reflection:
(set! *warn-on-reflection* true)
(def s "1")
(-> s .toString)
;; Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
;;= "1"
This doesn't:
(-> ^String s .toString)
;;= "1"
Maybe if you share a specific expression where you are finding it hard or impossible to type hint we can help you better.
There is a known situation where the type hint attached to the macro's &form expression is discarded, see this JIRA ticket Macroexpansion discards &form metadata. Maybe this is what you are seeing?
Yes, it is possible.
If you need to type-hint the initial argument to ->, you can do it directly, either inside or outside the -> form:
(-> ^String (foo) .toUpperCase)
(let [^String f (foo)]
(-> f .toUpperCase))
There will be no reflection in either case.
If the value that you wish to type-hint arises at an intermediate step in the -> chain, then you can type-hint it by putting the type hint on the -> step:
;; note the type hints on identity and (identity)
(-> ^String (foo) .toUpperCase ^String identity .toLowerCase)
(-> ^String (foo) .toUpperCase ^String (identity). toLowerCase)
Again, there will be no reflection in either case.
(Tested at a 1.7.0-alpha5 REPL.)
Well, in your case at least, there are no reflection penalties.
user=> (set! *warn-on-reflection* true)
true
user=> (-> "a b c " .toUpperCase (.replace "A" "X") (.split " ") first)
"X"
If you want to be even more sure:
user=> (def i 23)
#'user/i
user=> (.toString i)
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field toString can't be resolved.
"23"

Clojure: Reversing the parameters of contains? for use in condp

I discovered this clojure problem today:
(condp contains? some-set
"foo" "foo's in thar"
"bar" "bar's in thar"
"t'aint thar")
The idea is to return the string under the first match where some-set contains a value. If none of the values is in the set, it returns the last value. Problem is, the contains? function takes the collection first then the key and condp needs the key first.
I "fixed" it by writing a function:
(defn reverse-params [f] (fn [a b] (f b a))
and substituting a call to it:
(condp (reverse-params contains?) some-set
"foo" "foo's in thar"
"bar" "bar's in thar"
"t'aint thar")
Which works, but my question is am I missing some better way to do this (maybe by using some)? I could use cond but I figured this way saves me some typing.
Nope, you're not missing something. This is a normal way of going about it.
I often use an anonymous function for this if it will only be used once.
(condp #(contains? %2 %1) some-set
"foo" "foo's in thar"
"bar" "bar's in thar"
"t'aint thar")
This problem also comes up when threading things with the -> and ->> macros. In those cases I'll often use the as-> macro to give the threaded value a name

Clojure looping based on user input

In Clojure I want to create a function that would continually ask the user for an option, execute some code depending on the option, and then quit when the user’s option is “q”.
I am comfortable will all of the various Clojure forms that work with sequences, and I could certainly finagle a Java-like solution to the above, but I cannot figure out how to do this in a “clojuresque” manner.
Thanks,
Jeffrey S
Something like this should do the job:
(defn main-loop []
(case (read-line)
"q" nil
"a" (do (println "got a command!") (recur))
"b" (do (println "got b command!") (recur))
(do (println "got invalid command!") (recur))))

How can I evaluate "symbol" and "(symbol 1)" with the same name?

I want to get following results when I evaluate edit-url and (edit-url 1).
edit-url --> "/articles/:id/edit"
(edit-url 1) --> "/articles/1/edit"
Is it possible to define such a Var or something?
Now, I use following function, but I don't want to write (edit-url) to get const string.
(defn edit-url
([] "/articles/:id/edit")
([id] (str "/articles/" id "/edit")))
Thanks in advance.
If those behaviors are exactly what you want, print-method and tagged literals may be used to imitate them.
(defrecord Path [path]
clojure.lang.IFn
(invoke [this n]
(clojure.string/replace path ":id" (str n))))
(defmethod print-method Path [o ^java.io.Writer w]
(.write w (str "#path\"" (:path o) "\"")))
(set! *data-readers* (assoc *data-readers* 'path ->Path))
(comment
user=> (def p #path"/articles/:id/edit")
#'user/p
user=> p
#path"/articles/:id/edit"
user=> (p 1)
"/articles/1/edit"
user=>
)
edit-url will either have the value of an immutable string or function. Not both.
The problem will fade when you write a function with better abstraction that takes a string and a map of keywords to replace with words. It should work like this
(generate-url "/articles/:id/edit" {:id 1})
Clojure is a "Lisp 1" which means that is has a single namespace for all symbols, including both data scalars and functions. What you have written shows the functionally of both a string and a function but for a single name, which you can do in Common Lisp but not Clojure (not that a "Lisp 2" has its own inconveniences as well).
In general this type of "problem" is a non issue if you organize your vars better. Why not just make edit-url a function with variable arity? Without arguments it returns something, with arguments it returns something else. Really the possibilities are endless, even more so when you consider making a macro instead of a function (not that I'm advocating that).