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
Related
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
Let us say we had something like this:
(defstruct test :val :func)
(defn create-test
[]
(struct test 2 #(A)))
Is it somehow possible to reference :val from inside the provided function (that is, where A is located)?
This is a variant of the problem of cyclic references; lazy definitions allow the construction of these.
While Clojure's approach here isn't quite as elegant as the linked Haskell version, promise allows you to put a lazy reference to the function in the map and then define the function to the compiler in an environment in which the map and its values are accessible:
(def knot-tying
(let[{:keys[val func] :as knot} {:val "foo" :func (promise)}
f (fn[](str val "bar"))]
(deliver func f)
knot))
((deref (:func knot-tying))) ;;=>"foobar"
Or if you prefer tying "in the other direction" and having the function use deref instead of having to deref it:
(def knot-tying-2
(let[knot (promise)
f (fn[] (str (-> knot deref :val) "bar"))
tied {:val "foo" :func f}]
(deliver knot tied)
tied))
((:func knot-tying-2)) ;;=>"foobar"
No. Given an object, it is not generally possible to find which other objects reference it. Since Clojure maps and functions are immutable, you must first create the function and then the map, so there is no way for the function to access the map unless it is somehow passed the map after it is created.
However, assuming that you can create the function after the other value, you can allow the function to directly access the value (but not the containing map) using a closure:
((:function
(let [value 2
function #(str "The value is: " value)]
{:value value
:function function})))
;=> "The value is: 2"
I have a function that i need to take in a word and im trying to make a variable x the sorted version of word variable. Im not sure how i go about doing this... i am trying to pass it in as a parameter for a function but not working.
How do i pass in a "word" and make a variable within the function equal to a sorted version of "word" so i have two copies, the original word and the x version of word. So i can then go on to pass into a map i need to create.
(for [wordset '("one" "two" "three" "FouR" "wot" "Rheet" "nope" "#")]
(transform2 wordset))
(defn transform2 [word x]
(let [x (sort-string (str/lower-case word))]
(prn x)))
(defn sort-string [s]
(apply str (sort s)))
This is the error im getting back
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH:108:1)
This expression is doing nothing for you:
(for [wordset '("one" "two" "three" "FouR" "wot" "Rheet" "nope" "#")]
(transform2 wordset))
You are not placing this anywhere where the return value will be used. A for is not like an imperative for loop in other languages. It just creates a sequence and returns it, it is not modifying anything.
Also you should use vectors and prefer keywords, in general:
[:one :two :three :whatever]
Though that would change the semantics of what you're doing, so maybe you have strings coming in from somewhere else and need to use them? Otherwise, don't use strings yourself as identifiers: that's what keywords are for.
As for your other questions, it's not quite clear what you mean. You say you'd like to make a variable, but it's not clear what you mean by this, as the code you have isn't doing anything along those lines.
Your transform2 accepts two arguments but you're passing only one. Try removing the x argument like below. Also, you may want to reverse the order you create the functions because they need to be defined before being used. (You may also use declare.)
(defn sort-string [s]
(apply str (sort s)))
(defn transform2 [word]
(let [x (sort-string (clojure.string/lower-case word))]
(prn x)))
(for [wordset '("one" "two" "three" "FouR" "wot" "Rheet" "nope" "#")]
(transform2 wordset))
Result will be:
"eno"
"otw"
"eehrt"
"foru"
"otw"
"eehrt"
"enop"
"#"
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).
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)