Is it possible to write e.g. a Vector literal which uses a variable inside so that the variable gets evaluated correctly and the resulting Vector doesn't just contain the name/symbol of the variable?
For example:
(setq inner ["d" "e"])
["a" "b" inner]
Results into:
["a" "b" inner]
But what I would want is:
["a" "b" ["d" "e"]]
I've done some Clojure coding before Elisp, there it works as I expected:
(def inner ["d" "e"])
user=> ["a" "b" inner]
["a" "b" ["d" "e"]]
What's the fundamental thing I don't understand about Elisp here? I can of course work around this, but I'd like to understand what's going on.
When using the vector syntax, the elements are considered constant. From the Emacs Lisp Reference Manual 6.4:
A vector, like a string or a number, is considered a constant for
evaluation: the result of evaluating it is the same vector. This does
not evaluate or even examine the elements of the vector.
On the other hand, you could use the vector function to create a vector where the elements are evaluated:
(setq inner ["d" "e"])
(vector "a" "b" inner)
=> ["a" "b" ["d" "e"]]
use backquote literal. It's possible to use as same as for list.
(setq inner ["d" "e"])
`["a" "b" ,inner]
=> ["a" "b" ["d" "e"]]
Related
According to the Learning Clojure wikibook backticks are expanded as follows
`(x1 x2 x3 ... xn)
is interpreted to mean
(clojure.core/seq (clojure.core/concat |x1| |x2| |x3| ... |xn|))
Why wrap concat with seq? What difference does it make?
Regardless of how it arose
concat returns a sequence, and
seq returns a sequence with the same content as its sequence argument,
... so seq is effectively an identity-op on a concat... except in one circumstance:
When s is an empty sequence, (seq s) is nil.
I doubt that the expansion is correct, since
`()
... evaluates to
()
... with type
clojure.lang.PersistentList$EmptyList
Whereas
(seq (concat))
... evaluates to
nil
This suggests that the wrapping call to seq is not there.
Strictly speaking, it expands to:
(macroexpand '`(x1 x2 x3))
(clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/x1)) (clojure.core/list (quote user/x2)) (clojure.core/list (quote user/x3))))
(macroexpand `(x1 x2 x3))
(user/x1 user/x2 user/x3)
Why the call seq ? Because sequences are corner stones in Clojure philosophy. I recommend you read Clojure Sequences. Otherwise, I would duplicate it here.
I'm trying to solve a problem: I need to create a map from passed-in values, but while the symbol names for the values are consistent, the keys they map to are not. For instance: I might be passed a value that is a user ID. In the code, I can always use the symbol user-id -- but depending on other factors, I might need to make a map {"userId" user-id} or {"user_id" user-id} or {:user-id user-id} or -- well, you get the picture.
I can write a macro that gets me part-way there:
(defmacro user1 [user-id] `{"userId" ~user-id}
(defmacro user2 [user-id] `{"user_id" ~user-id}
But what I'd much rather do is define a set of maps, then combine them with a given set of symbols:
(def user-id-map-1 `{"userId" `user-id}
(defn combiner [m user-id] m) ;; <-- Around here, a miracle occurs.
I can't figure out how to get this evaluation to occur. It seems like I should be able to make a map containing un-evaluated symbols, then look up those symbols in the lexical scope of a function or macro that binds those symbols as locals -- but how?
Instead of standardizing your symbolic names, use maps with standard keyword keys. You don't need to go near macros, and you can turn your maps into records if need be without much trouble.
What you know as
(def user1 {:id 3124, :surname "Adabolo", :forenames ["Julia" "Frances"]})
... can be transformed by mapping the keys with whatever function you choose:
(defn map-keys [keymap m]
(zipmap (map keymap (keys m)) (vals m)))
For example,
(map-keys name user1)
;{"id" 3124, "surname" "Adabolo", "forenames" ["Julia" "Frances"]}
or
(map-keys {:id :user-id, :surname :family-name} user1)
;{:user-id 3124, :family-name "Adabolo", nil ["Julia" "Frances"]}
If you want rid of the nil entry, wrap the expression in (dissoc ... nil):
(defn map-keys [keymap m]
(dissoc
(zipmap (map keymap (keys m)) (vals m))
nil))
Then
(map-keys {:id :user-id, :surname :family-name} user1)
;{:user-id 3124, :family-name "Adabolo"}
I see from MichaĆ Marczyk's answer, which has priority, that the above essentially rewrites clojure.set/rename-keys, which, however ...
leaves missing keys untouched:
For example,
(clojure.set/rename-keys user1 {:id :user-id, :surname :family-name})
;{:user-id 3124, :forenames ["Julia" "Frances"], :family-name "Adabolo"}
doesn't work with normal functions:
For example,
(clojure.set/rename-keys user1 name)
;IllegalArgumentException Don't know how to create ISeq from: clojure.core$name ...
If you forego the use of false and nil as keys, you can leave missing keys untouched and still use normal functions:
(defn map-keys [keymap m]
(zipmap (map #(or (keymap %) %) (keys m)) (vals m)))
Then
(map-keys {:id :user-id, :surname :family-name} user1)
;{:user-id 3124, :family-name "Adabolo", :forenames ["Julia" "Frances"]}
How about putting your passed-in values in a map keyed by keywords forged from the formal parameter names:
(defmacro zipfn [map-name arglist & body]
`(fn ~arglist
(let [~map-name (zipmap ~(mapv keyword arglist) ~arglist)]
~#body)))
Example of use:
((zipfn argmap [x y z]
argmap)
1 2 3)
;= {:z 3, :y 2, :x 1}
Better yet, don't use macros:
;; could take varargs for ks (though it would then need another name)
(defn curried-zipmap [ks]
#(zipmap ks %))
((curried-zipmap [:x :y :z]) [1 2 3])
;= {:z 3, :y 2, :x 1}
Then you could rekey this map using clojure.set/rename-keys:
(clojure.set/rename-keys {:z 3, :y 2, :x 1} {:z "z" :y "y" :x "x"})
;= {"x" 1, "z" 3, "y" 2}
The second map here is the "translation map" for the keys; you can construct in by merging maps like {:x "x"} describing how the individual keys ought to be renamed.
For the problem you described I can't find a reason to use macros.
I'd recommend something like
(defn assoc-user-id
[m user-id other-factors]
(assoc m (key-for other-factors) user-id))
Where you implement key-for so that it selects the key based on other-factors.
mydata is about use`s name and gender:
(def mydata [["a" 'f] ["b" 'm]])
what I want is:
(group-by #(let [[name gender] %1] name) mydata)
; {"a" [["a" f]], "b" [["b" m]]}
and also:
(group-by #(let [[name gender] %1] gender) mydata)
; {f [["a" f]], m [["b" m]]}
so I want build a function like this:
(defn my-group-by [data, field]
(group-by #(let [[name gender] %1] field) mydata))
but it go wrong
(mygroup-by mydata 'name)
; {name [["a" :F] ["b" :M]]}
and then I thought macro could do that
(defmacro my-macro [data field]
`(group-by #(let [[name,gender] %1] ~field) ~data))
then I run it
(my-macro mydata name)
; CompilerException java.lang.RuntimeException: Can't let qualified name: clojure.core/name, compiling:(/tmp/form-init2648255959159095748.clj:1:1)
why? Where I`m wrong?
There is no need to use macros for this.
If you represent your data as a sequence of maps:
(def mydata [{:name "a", :gender :F}
{:name "b", :gender :M}
{:name "a", :gender :M}]) ; extra line
... then you can use the keywords of the maps as functions:
(group-by :gender mydata)
{:F [{:gender :F, :name "a"}],
:M [{:gender :M, :name "b"} {:gender :M, :name "a"}]}
and
(group-by :name mydata)
{"a" [{:gender :F, :name "a"} {:gender :M, :name "a"}],
"b" [{:gender :M, :name "b"}]}
If maps prove to be too slow, you can turn them into records:
(defrecord user [name gender])
(def mydata [(map->user {:name "a", :gender :F})
(map->user {:name "b", :gender :M})
(map->user {:name "a", :gender :M})])
... which work as the maps do.
Using macro is a bit overkill here.
Using map and sort by its key is more common.
If you do need to sort using your own vector structure, here is one way to do it:
(defn my-group-by [data field]
(group-by
#(nth % (.indexOf ['name 'gender] field))
data))
Then, using it like
(my-group-by mydata 'name)
(my-group-by mydata 'gender)
Yet I would personally replace all occurrences of 'name with "name", 'gender with "gender".
For the macro error :
In a macro you have to postfix local variables with # to avoid scope problem with values passed as arguments to the macro... You cannot refer from out of the macro to a variable that is defined inside the macro... and that was exactly what you wanted to do. Macro arguments are values, it's not a rewriting process as in C macros.
(defmacro my-macro [data field]
(group-by #(let [[name# gender#] %1] ~field) ~data))
You would have to pass name# or gender# to the macro but it has no sense as it's not defined outside the macro... So the solution given by Thumbnail is the correct one.
But you can do (just for info as it's not a correct solution):
(defmacro my-macro-name [data]
`(group-by #(let [[name# _] %1] name#) ~data))
But in this case it's obviously easier to do as alfredx wrote, but I would prefer to use keywords :
(defn my-fn [data field]
(group-by #(nth % (.indexOf [:name :gender] field)) data))
Coming from other programming languages, I would expect the following statements to all produce the same result. Can someone explain why the parenthesis make a difference here?
PS D:\> "ab", "cd"
ab
cd
PS D:\> "a"+"b" , "c"+"d"
ab cd
PS D:\> "a"+"b" , ("c"+"d")
ab cd
PS D:\> ("a"+"b"), "c"+"d"
ab
c
d
PS D:\> ("a"+"b"), ("c"+"d")
ab
cd
PS D:\>
The applicable rules are as follows:
The , is a unary or binary operator that creates an array of the operand(s), and it has higher precedence than the + operator.
The + operator can be used for numerical addition, string concatenation, and array concatenation. The data type of the left operand determines which type of operation is performed. If possible, the right operand is cast as the data type of the left operand; if not possible, an error is thrown. *
Where precedence is equal, evaluation occurs left to right.
Arrays are cast as strings by listing the elements separated by spaces.
Parentheses, as you'd expect, have higher precedence than any operator, and cause the enclosed expression to be evaluated before anything outside the parentheses.
The default output of an array object is a list of elements, one on each line.
* That explains seemingly inconsistent results such as that "foo" + 1 evaluates to foo1, but 1 + "foo" gives you an error.
So, let's take a look at your test cases, and analyze what happens following the logic explained above.
Case I:
"ab", "cd"
This one is very straightforward: the , operator creates an array of two strings, ab and bc.
Case II:
"a" + "b", "c" + "d"
This one seems counter-intuitive at a first glance; the key is to realize that , is evaluated before +. Here's how the result is obtained, step by step:
"b", "c" is evaluated first (due to ,'s precedence over +), creating an array of the elements b and c.
Next, the + operator is applied to "a" and the array created in step 1. Since the left operand "a" is a string, a string concatenation is performed.
To concatenate a string with an array, the array is cast as a string. An array of b and c becomes the string b c.
Concatenating a with b c yields ab c.
Finally, ab c is concatenated with d to produce the final result, ab cd
Case III:
"a"+"b" , ("c"+"d")
This yields the same result by coincidence; the evaluation occurs differently:
("c"+"d") is evaluated first, due to the parentheses. That's a plain vanilla string concatenation, which results in the string cd.
Next, the , operator is applied to "b" and the string from step 1, creating an array of the elements b and cd. (This is evaluated before "a" + "b" because , has higher precedence than +.)
Then, the + operator is applied to "a" and the array created in step 2. Since the left operand is a string, a string concatenation is performed.
The array of b and cd is cast as the string b cd.
The strings a and b cd are concatenated, resulting in the final output ab cd.
Case IV:
("a" + "b"), "c" + "d"
This is the most interesting test case, and probably the most counter-intuitive, because it yields results that may appear inconsistent. Here's how it's evaluated:
Similar to Case III step 1, ("a" + "b") is evaluated first, producing the string ab.
The , is applied to the string from step 1 and "c", creating an array of the elements ab and c.
The + operator is applied to the array from step 2 and the next token, "d". This time, the left operand is an array, so an array concatenation is performed.
The string operand "d" is cast as an array of one element.
The two arrays are concatenated into an array of the elements ab, c, and d.
Case V:
("a" + "b"), ("c" + "d")
By now, it should be easy to see what happens here:
("a" + "b") is evaluated as the string ab.
("c" + "d") is evaluated as the string cd.
The , is applied to the strings from steps 1 and 2, creating an array of ab and cd.
You can see the precedence table with the command
Get-Help about_Operator_Precedence
(Help doc names can be tab-completed, so to save typing, that's help about_opTABTAB)
I want to make a local instance of a Java Scanner class in a clojure program. Why does this not work:
; gives me: count not supported on this type: Symbol
(let s (new Scanner "a b c"))
but it will let me create a global instance like this:
(def s (new Scanner "a b c"))
I was under the impression that the only difference was scope, but apparently not. What is the difference between let and def?
The problem is that your use of let is wrong.
let works like this:
(let [identifier (expr)])
So your example should be something like this:
(let [s (Scanner. "a b c")]
(exprs))
You can only use the lexical bindings made with let within the scope of let (the opening and closing parens). Let just creates a set of lexical bindings. I use def for making a global binding and lets for binding something I want only in the scope of the let as it keeps things clean. They both have their uses.
NOTE: (Class.) is the same as (new Class), it's just syntactic sugar.
LET is not "make a lexical binding in the current scope", but "make a new lexical scope with the following bindings".
(let [s (foo whatever)]
;; s is bound here
)
;; but not here
(def s (foo whatever))
;; s is bound here
Simplified: def is for global constants, let is for local variables.
Correct syntax:
(let [s (Scanner. "a b c")] ...)
The syntax for them is different, even if the meanings are related.
let takes a list of bindings (name value pairs) followed by expressions to evaluate in the context of those binding.
def just takes one binding, not a list, and adds it to the global context.
You could think of let as syntactic sugar for creating a new lexical scope with fn then applying it immediately:
(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
So you could implement let with a simple macro and fn:
(defmacro fnlet [bindings & body]
((fn [pairs]
`((fn [~#(map first pairs)] ~#body) ~#(map last pairs)))
(partition 2 bindings)))
(fnlet [a 3 b 7] (* a b)) ; 21