clojure dynamic binding, read-string and eval Unable to resolve symbol - multithreading

(declare ^:dynamic symbol-table)
(defn answer []
(prn "blah")
(binding [symbol-table {:answer 42}]
(-> "[:h1 (:answer symbol-table)]" read-string eval)))
The above code runs as expected when executed at the repl. it returns
cpress.hsp> (answer)
"blah"
[:h1 42]
However, when it is executed in a thread spawn by http-kit, I get an unable to resolve symbol
Exception in thread "Thread-43"
java.lang.RuntimeException: Unable to resolve symbol: symbol-table in this context, compiling:(NO_SOURCE_PATH:0:0)
at clojure.lang.Compiler.analyze(Compiler.java:6792)
at clojure.lang.Compiler.analyze(Compiler.java:6729)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3874)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7005)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
to simulate this at the repl spawn a thread to run the answer function
(.. (Thread. answer) start)
Why does this happen and how to fix it?
Some experimentation shows that it can't find the symbol due to namespace.
for example, instead of getting the expression from read-string, i put in a literal
(defn answer2 []
(binding [symbol-table {:answer 42}]
(prn (eval `[:h1 (:answer symbol-table)])) ;;works
;;(eval '[:h1 (:answer symbol-table)]) ;; does not works
))
the first eval uses syntax quoting which works, but when i use regular quoting it doesn't work. syntax quoting resolves namespace while regular quoting does not. if read-string returned an expression with namespace qualified symbols then it would solve my problem I think, but read-string does not

When you run eval, unqualified symbols in the form are resolved in the current namespace at runtime (not that of the namespace where the function is defined).
To solve this, you can create a version of eval with the namespace bound to the one you need:
(defn local-eval [x]
(binding [*ns* (find-ns 'my-namespace)]
(eval x)))
(Obviously you need to change my-namespace to reflect the right name). Then you use that instead:
(defn answer []
(binding [symbol-table {:answer 42}]
(-> "[:h1 (:answer symbol-table)]" read-string local-eval)))

Related

Is there a way to create a string in a function from a list in another function in Clojure?

Im pretty new to Clojure and functional programming, im trying to use two functions to concatenate some chars intro a string. My idea is basically like this:
(defn receive [char-from-list]
(str char-from-list))
(defn send-char [list-char]
(if (empty? list-char)
(receive nil)
((receive (first list-char))(send-char (rest list-char)))))
So the idea is that I start with the function send and as a parameter write a list of chars like this:
(send-char '(\h \e \l \l \o))
The receive function with get sent one char at a time and using str it will add them all together and my final output would be: "hello".
When I try to run the code this error appears:
Execution error (ClassCastException) at automata.core/send-char (core.clj:44).
class java.lang.String cannot be cast to class clojure.lang.IFn (java.lang.String is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')
Im not sure if there a way to do this or another method but I don't know how, please help. Thanks
The error is because you have 2 left parentheses in a row here:
((receive ...
Remember, in Clojure a left paren means "function call", and a string is not a function (function receive returns a string).
If you have 2 things you want to group in Clojure, you need to use a do form like:
(defn send-char [chars]
(if (empty? chars)
(receive nil)
(do
(receive (first chars))
(send-char (rest chars)))))
Having identified the source of the error, your original question still is very vague and undefined. Here are 3 ways of joining a sequence of characters into a string:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.string :as str]))
(dotest
(let-spy [chars (vec "hello")
s0 (apply str chars)
s1 (str/join chars)
s2 (reduce str "" chars)
]
(is= chars [\h \e \l \l \o])
(is= s0 "hello")
(is= s1 "hello")
(is= s2 "hello")
))
The above is based on my favorite template project. Be sure to also study the list of documentation sources.

r5rs eval not finding reference within its lexical scope

If eval with (interaction-environment) should have access to everything that's defined within the lexical scope of when it's called, then why am I getting this error when I try to run the below code?
Welcome to DrRacket, version 6.3 [3m].
Language: R5RS; memory limit: 128 MB.
why does this work? object_function: undefined;
cannot reference undefined identifier
Code:
(define (disp x)
(display x))
(eval '(disp "why does this work?") (interaction-environment))
;The below doesn't work
((lambda ()
(define (object_function x)
(display x))
(eval '(object_function "But not this?") (interaction-environment))))
(define (object)
(define (object_function x)
(display x))
(eval '(object_function "And not this?") (interaction-environment)))
(object)
If I change it like so:
;The below does work
(define (object_function x)
(display x))
((lambda ()
(eval '(object_function "Why does it work now?") (interaction-environment))))
(define (object)
(eval '(object_function "And now?") (interaction-environment)))
(object)
Output:
Welcome to DrRacket, version 6.3 [3m].
Language: R5RS; memory limit: 128 MB.
Why does it work now?And now?
With eval by itself it works just fine, but wrap it in a defined function or a lambda and it can't find the locally defined function that is within the same scope that the eval function is called.
I may be misunderstanding how eval or interaction-environment deal with lexical scope, but if someone can shed some light on this that would be helpful.
When eval evaluates data it does so at top level. The lexical depth from where you call eval is not leaked into the evaluation. The second argument only changes between the three different global environments you can access.
define inside a procedure or let is just a fancy letrec and thus a lexical binding. It will not be available from eval. Top level define makes a global binding and it will be available from eval iff interaction-environment is used.
Implementations don't have to implement interaction-environment, as it is optional. The required environments are null-environment, that only have special forms, and scheme-report-environment, which is the initial environment of the system.
eval is a powerful feature that is usually the wrong solution. Usually you are doing it wrong if you need to use eval.

Pass an object argument to a macro

I encounter errors when passing an object argument to a macro. Must I quote the argument, put it in a list, or not quote it?
I wish to use Clozure Common Lisp to generate and run multiple processes in parallel using a read-write-lock to control data output to another process. With-write-lock is a macro that waits until the given lock is available for write access, then executes its body with the lock held. However, I get errors no matter how I try to pass the lock to with-write-lock. I'm having trouble I think because I fail to understand how to pass a lock object to the with-write-lock macro. If I bind the lock to a symbol I get destructuring errors:
(let ((l (make-read-write-lock)))
(with-write-lock l (1+ 1)))
==>
> Error: L can't be destructured against the lambda list (LOCK), because it is not a proper list.
While executing: (:INTERNAL CCL::NX1-COMPILE-LAMBDA), in process Listener(4).
but if I pass the call to make-read-write-lock as the lock argument to with-write-lock then I get an undeclared free variable error:
(with-write-lock (make-read-write-lock) (1+ 1))
==>
;Compiler warnings for "/Users/frank/Documents/Lisp/threaded/act-parallel.lisp" :
;In an anonymous lambda form at position 18: Undeclared free variable MAKE-READ-WRITE-LOCK
Error: Unbound variable: MAKE-READ-WRITE-LOCK
While executing: #, in process Listener(4).
Am I failing because I misunderstand how to pass an object to a macro or am I going awry because or something more particular to with-write-lock?
Here's the with-write-lock macro that comes with Clozure Common Lisp (macros.lisp):
(defmacro with-write-lock ((lock) &body body)
(let* ((locked (gensym))
(p (gensym)))
`(with-lock-context
(let* ((,locked (make-lock-acquisition))
(,p ,lock))
(declare (dynamic-extent ,locked))
(unwind-protect
(progn
(write-lock-rwlock ,p ,locked)
,#body)
(when (lock-acquisition.status ,locked) (unlock-rwlock ,p)))))))
The lambda list for that macro is destructuring its arguments.
((lock) &body body)
Means that it wants the first argument as a list which contains the lock and then the body form. This is a pretty standard macro argument list in CL, you can use it like this:
(with-write-lock (lock)
..... body forms ....)
So your examples would be
(let ((l (make-read-write-lock)))
(with-write-lock (l) (1+ 1)))
And:
(with-write-lock ((make-read-write-lock)) (1+ 1))
respectively. Note the extra parens around the first argument.
For similar macros see with-open-file or destructuring-bind
(with-open-file ("path/to/file" :open :args)
.... body ...)
(destructuring-bind (one two three) '(1 2 3)
.... body forms ...)

Want to access lexically defined functions using EVAL in CLISP

Why won't this piece of code work?
(setf x '(foo bar (baz)))
(labels
((baz () (print "baz here")))
(baz) ;works
(eval (third x))) ;fails with the below message
*** - EVAL: undefined function BAZ
I'm using GNU CLISP.
In Common Lisp, eval evaluates its argument in a null lexical environment, so your lexically bound function baz can't be found.
While the Common Lisp standard doesn't provide a portable way to access the lexical environment and invoke eval with it, your implementation might have this functionality. For example, in CLISP:
cs-user> (setf x '(foo bar (baz)))
(foo bar (baz))
cs-user> (labels ((baz () (print "baz here")))
(eval-env (third x) (the-environment)))
"baz here"
"baz here"
cs-user>
See geocar's answer for other approaches.
Because common lisp doesn't have special functions.
Check the description of EVAL:
Evaluates form in the current dynamic environment and the null lexical environment.
Since the lexical environment is empty, your baz function (defined by labels) isn't accessible. You'd think you could fix this by putting baz in the dynamic environment (you might want something like (declare (special baz)) or (declare (special (function baz))) or something like this) but alas: there's no way to do this.
You could simulate it yourself by creating:
(defvar baz* nil)
(defun baz (&rest args) (apply baz* args))
You then need to dynamically set baz* instead of using labels:
(setf x '(foo bar (baz)))
(let ((baz* (lambda () (print "baz here"))))
(eval (third x)))
The reason why is just some hard bits about optimisation leaking into the spec. Basically, every function-call would need some stubbing unless the compiler could prove that the function would never get defined dynamically swizzleable. That's hard to do efficiently, and it's not something most CL programmers ever did, so the spec-writers simply forbade it.
As you can see, and as with most things in CL, you can easily get it yourself if you need it. However. Given that most CL programmers never do this, you may want to re-examine why you're trying to do things this way.

How do I pass a static method to comp in clojure?

It seems as though I'm having problems accessing Integer.parseInt in comp. I can access it normally like this:
user=> (Integer/parseInt "123")
123
But if I put it in comp, I get an error:
user=> (def vect-to-int (comp Integer/parseInt (partial apply str)))
java.lang.Exception: Unable to find static field: parseInt in class java.lang.Integer (NO_SOURCE_FILE:3)
It sounds to me like it's trying to find a field on Integer when it should be looking for a method. How can I use Integer.parseInt like this? And is there a better way to convert a vector of chars into an int?
Clojure functions are java methods but java methods are not clojure functions For instance Clojure functions have meta-data and such. If you want to use a java method where a Clojure function is called for then you have two choices in wrapping it up, memfn and fun or #( ) memfn is an obsolete function that wrapped up a java method in a clojure function (its good to know it exists even if its not used often). The generally accepted way to wrap up java methods is:
#(. instance method arg1 argN)
or for static methods
#(Class/MethodName arg1 argN)
(def vec-to-int (comp #(Integer/parseInt %) (partial apply str)))
Or
(def vec-to-int #(Integer/parseInt (apply str %)))
partial and comp usually aren't as succinct in Clojure as using #() to make an anonymous fn. Personally I'd write it this way:
(defn vec-to-int [x] (Integer/parseInt (apply str x)))
You can do this with plain def, but what do you gain using def instead of defn, really? Using def obscures the fact that you're defining a function. defn also sets up additional metadata for you (arglists) that def doesn't.
In any case, this is a more general way to do what you're doing:
(def vec-to-int #(bigint (apply str %)))
And still more general:
(def vec-to-int #(read-string (apply str %)))
Depends whether you want to be able to handle things other than Integers.

Resources