I'm a novice in clojure and java.
In order to access a Java field in Clojure you can do:
Classname/staticField
which is just the same as
(. Classname staticField)
(correct me if I'm wrong)
How can I access a static field when the name of the field in held within a variable? i.e.:
(let [key-stroke 'VK_L
key-event KeyEvent/key-stroke])
I want key-stroke to be evaluated into the symbol VK_L before it tries to access the field.
In this case you might want to do something like the following:
user=> (def m 'parseInt)
#'user/m
user=> `(. Integer ~m "10")
(. java.lang.Integer parseInt "10")
user=> (eval `(. Integer ~m "10"))
10
If you feel like it's a bit hack-ish, it's because it really is such. There might be better ways to structure the code, but at least this should work.
I made a small clojure library that translates public fields to clojure maps using the reflection API:
(ns your.namespace
(:use nl.zeekat.java.fields))
(deftype TestType
[field1 field2])
; fully dynamic:
(fields (TestType. 1 2))
=> {:field1 1 :field2 2}
; optimized for specific class:
(def-fields rec-map TestType)
(rec-map (TestType. 1 2))
=> {:field1 1 :field2 2}
See https://github.com/joodie/clj-java-fields
Reflection is probably the proper route to take, but the easiest way is
(eval (read-string (str "KeyEvent/" key-stroke)))
This will just convert the generated string into valid clojure and then evaluate it.
You can construct the right call as an s-expression and evaluate it as follows:
(let [key-stroke 'VK_L
key-event (eval `(. KeyEvent ~key-stroke))]
....do things with your key-event......)
However, if what you are trying to do is test whether a particular key has been pressed, you may not need any of this: I usually find that it is easiest to write code something like:
(cond
(= KeyEvent/VK_L key-value)
"Handle L"
(= KeyEvent/VK_M key-value)
"Handle M"
:else
"Handle some other key")
Related
I created a function which gets two string parameters. The function simply adds each string length. below is a code.
(defun add_twostring_length (mystr1 mystr2)
(+ (length mystr1) (length mystr2))
)
When I call add_twostring_length function like this,
(add_twostring_length "cpp" "lisp")
output is correct. 7
But, when I call the same function in the manner of using comma,
(add_twostring_length "cpp", "lisp")
I got an error message.
Error: Comma not inside a backquote.
[condition type: READER-ERROR]
I want to call function in the manner of (add_twostring_length "cpp", "lisp").
What is the wrong with the code?
picture showing error message
You might as well ask "why can't I call the function without parentheses?" In lisp, you call functions as an sexpr with the function in the car and the arguments in the cdr. There are no commas involved -- that's the syntax of lisp.
What you want is possible, but I will strongly advice against using it:
(set-macro-character #\,
#'(lambda (stream char)
(read stream t nil t)))
The above code creates the so called "read macro". At read-time common lisp will find all occurrences of , and ignore them. This makes possible calling functions like so:
(+ 1, 2, 3) ; => 6
However this will break escaping in templates:
`(1 2 ,(+ 3 4)) ; => (1 2 (+ 3 4))
Perhaps it is possible to make the read macro more intelligent, but I don't want to delve deeper into this, because I don't like the idea. Sorry.
Assume the following,
(in-ns silly.fun)
(def a 1)
(defn fx [b]
((fn [c] (return-all-symbols)) (first b)))
I was wondering if it is possible to have a return-all-symbols function that would return the map of symbols/values currently scoped at its invocation. So, assuming the above was compiled and we were in the 'silly.fun namespace, we could run something like the following.
(fx [:hello]) => {"a" 1, "b" [:hello], "c" :hello}
I would like to use return-all-symbols for debugging purposes. Is return-all-symbols at all possible? If so, what is its implementation?
It's possible, but as you've defined it you'd be pretty sad: you don't want a map with hundreds of entries referring to all the functions in clojure.core! And even if you only look in the current namespace, you forgot to include fx, which is a symbol whose value is a function. Plus there will often be lexical symbols you don't want, introduced by macros. eg, (let [[x y] foo]) would show four symbols available: foo, x, y, and something like vec__auto__4863.
Anyway, you probably have to live with some compromise over those issues, or else (and really I think this is better) specify which symbols you actually want a map of. But to automatically get values for those symbols which are either (a) lexical or (b) defined in the current namespace, and also (c) not mapping to a function, you could use:
(defmacro return-all-symbols []
(let [globals (remove (comp :macro meta val) (ns-publics *ns*))
syms (mapcat keys [globals, &env])
entries (for [sym syms]
[`(quote ~sym) sym])]
`(into {}
(for [[sym# value#] [~#entries]
:when (not (fn? value#))]
[sym# value#]))))
(def a 1)
(defn fx [b]
((fn [c] (return-all-symbols)) (first b)))
(fx [:hello])
;=> {a 1, c :hello, b [:hello]}
Namespaces contain a map with all the currently scoped vars, which gives you part of what you want. It would miss lexicaly scoped symbols from expressions like (let [x 4] (return-all-symbols)) though may still be useful for debugging:
core> (take 2 (ns-map *ns*))
([sorted-map #'clojure.core/sorted-map] [read-line #'clojure.core/read-line])
if you need more than this then you may need a real debugger that uses the java debugging
interface. check out the clojure debugging toolkit
(ns-interns) might be what you want, but using (ns-map) wrapped in (lazy-seq) works good for a big namespace.
1 (ns-map 'clojure.core)
2 {sorted-map #'clojure.core/sorted-map, read-line #'clojure.core/read-line, re-pattern #'clojure.core/re-pattern, keyword? #'clojure.core/keyword?, ClassVisitor clojure.asm.ClassVisitor, asm-type #'clojure.core/asm-type, val #'clojure.core/val, ...chop...}
Currently I'm trying to learn Clojure and I would like to write a function that has a variable amount of parameters. This function should filter every input to check if it's a string or not. If it does, every input of type string should be returned..
Clojure is hard for me and different way of thinking, but am I on the right direction here.. I can't seem to solve it:
(defn returnString [& y]
(if (next y)
(filter (fn [x] (= (type x) "java.lang.String"))y)
(recur (next x))))
Thanks!
There is a function called string? that returns true if the argument is a string, or false if not.
=> (string? "hi")
true
=> (string? 100)
false
=> (string? ["a" "b" "c"])
false
So with that in mind, your function would look like:
(defn return-strings [& vals]
(filter string? vals))
The filter function will return a sequence (essentially a collection) of values, so there is no need worry about recursion (that is, using recur) in your custom function for this case.
The anonymous function you use to determine what is a string is very close to being correct. If you take a look at the source for string? by entering (source string?) into your REPL, you'll see:
(fn [x] (instance? String x))
Although, the approach you are taking would work as well. You just need to specify the String class instead of the string value you were giving. (Note, you can leave off java.lang because that package is automatically included just like it is in Java.)
(fn [x] (= (type x) String))
I've been looking at the if-let and when-let macros, Im having trouble determining what exactly it is that they "do". In particular, the documentation sais :
clojure.core/when-let
([bindings & body])
Macro
bindings => binding-form test
When test is true, evaluates body with binding-form bound to the value of test
I thus am somewhat confused about the way macros are documented.
1) What does the "=>" symbol mean ?
2) What does "test" refer to ?
Direct answer to your questions:
=> means "expands to", as in BNF notation. In this case it means that you need two forms: binding-form and the test.
"test" means anything that can be evaluated as bool.
By the way, I think that the docs are unclear or even maybe erroneous here. It is hard (or impossible) to deduce that the two forms constituting the bindings need to be enclosed in a vector. IMHO it should be either when-let ([[bindings] & body]) (the vector shown in the args) or bindings => [binding-form test] (the vector shown in the BNF-like expansion.)
It's often helpful when dealing with a macro to call macroexpand and see what the generated code is.
(macroexpand
'(if-let [x (myfunc)]
(foo x)
(bar))
; expands to
(let* [temp__3695__auto__ (myfunc)]
(if temp__3695__auto__ (clojure.core/let [x temp__3695__auto__]
(foo x))
(bar)))
; the generated symbols are necessary to avoid symbol
; capture but can confuse. The above is equivalent to:
(let* [ t (myfunc)]
(if t
(let [x t]
(foo x))
(bar))
So you can see that if-let is a shorthand for "bind local variable to the result of a function call and if that variable is truthy call the first form, else call the other form. The value returned by your function is only available in the 'truthy' branch."
wrt documentation convention
bindings => binding-form test
=> reads something like 'is equivalent to'
test is some form that returns a value
For most of these functions, clojuredocs is your friend, example usage often clarify things. If the clojuredocs example doesn't cut it for you, you can add your own
Consider the following code:
(if-let [x (a-function)]
(do-something-with x) ;; (a-function) returned a truthy result
(do-something-else) ;; (a-function) returned nil or false
This is like let, in that x will be bound to the return value of (a-function). This function could return nil or false. In that case, the implicit test fails and (do-something-else) will be evaluated. If x is not nil and not false, (do-something-with x) will be evaluated.
A scenario where this could be useful:
(if-let [user (find-logged-in-user)]
(do something with logged in user) ;; a user was found
(redirect to login page) ;; no user was found
I sometimes use something like the following, to conditionally add keys to a map of options:
(apply merge {:username "joe"
:email "joe#example.com"}
(when-let [name (find-full-name)] {:name name})
(when-let [dob (find-date-of-birth)] {:dob dob}))
This results in a map with :username and :email keys, and a :name key if the users' full name was found, plus a :dob key if a date of birth was found.
I hope that makes the use of if-let and when-let clearer.
I'd like to export or replicate a scheme environment in another guile process. The algorithm I'm imagining would do something like this to serialize:
(map (lambda (var val) (display (quasiquote (define ,var ,val))
(newline))
(get-current-environment))
And then I'd read/eval that on the other end.
However, while there are functions that return the current environment, they are in some internal format that I can't just map across. How can I "walk" the environment as the above? Alternatively, how else can I replicate an environment into another process?
you may decompose the so-called "current-environment" like this:
(define (get-current-binding-list)
(let* ((e (current-module)) ;; assume checking current-module
(h (struct-ref e 0)) ;; index 0 is current vars hashtable
)
(hash-map->list cons h) ;; return a vars binding list
))
and you can call (get-current-binding-list) to get variables binding list in current-module.
Please note that each element in this list is a pair of symbol and variable type, say, (symbol-name . variable-type). So you may print it like this:
for a instance ,you got a var binding:
(define abc 5)
then:
(let ((vl (get-current-binding-list)))
(assoc-ref vl 'abc)
)
==> #<variable 9bb5108 value: 5>
This result is a "variable type" of variable "abc". You can get it's value with variable-ref procedure.
So you can trace all the bindings and do something ,in your code ,it's simply print var-name and var-value.
I know my answer is too brief, but I think there's enough information to help you to find more details in the manual.
Hope this will help you.
You can't really serialize Scheme environment. I don't known even it's possible to (portably) serialize continuations. Oh, and don't forget about FFIs. Ports and threads are unserializable too.