In Clojurescript, how do I pass a collection's elements as arguments to a variable arity Javascript function? - interop

This writes to console the way I would expect:
(.log js/console "hi" "there")
The output is
hi there
This, however, just writes a big mess to the console:
(defn log-it [& args] (.log js/console args))
(log-it "hello" "there")
The output is:
c…s.c…e.IndexedSeq {arr: Array[2], i: 0, meta: null, cljs$lang$protocol_mask$partition0$: 166592766, cljs$lang$protocol_mask$partition1$: 8192}
This also does NOT work:
(apply .log js/console ["hi" "there"])
Is there a way to pass the vector's elements into the .log function?
Do I have to write a macro to concat the vector on to '(.log js/console)?

The problem here is that you're trying to log the value of args (which is a Clojure IndexedSeq) rather than passing the values in the seq as individual arguments. In this case you need to use apply (or convert that sequence to a native data structure).
The reason your other example doesn't work should become clear if you look at the signature for apply.
(apply f args)
It expects the first argument to be the function you want to invoke, but here, the first argument is .log.
(apply .log js/console ["hi" "there"])
Remember that .log js/console is the syntax for invoking the log method on console. Instead, we want to get a reference to the console.log function.
(apply (.-log js/console) args)
We're using .-log to read the .log property, rather than call it as a method. Then we pass that along with our args sequence.
So instead, you can define the original function as:
(defn log-it
[& args]
(apply (.-log js/console) args))
Or if you want to get a little bit smarter.
(def log-it (partial (.-log js/console)))

Related

How to advice-add a function with no arguments to a function that takes arguments?

Say I have a functions as follows:
(defun my/test-a (n)
(interactive)
(message n))
(defun my/test-b ()
(interactive)
(sleep-for .5)
(message "Message - B.")
(sleep-for .5))
I then advice my/test-a with mytest-b like so: (advice-add 'my/test-a :after #'my/test-b).
However when I call (my/test-a "Message - A.") I get a "Wrong number of arguments" error. My understanding is that add-advice is feeding the argument into my/test-b, which is not expecting any arguments.
How to advice-add a function with no arguments to a function that takes arguments?
I could change my/test-b so it takes an argument and doesn't use it, but that feels very messy.
Related followup - how could I advise find-file with a function with no arguments (like my/test-b)? I understand find-file is an unusual case, because it doesn't need an argument if called interactively. But if I run (advice-add 'find-file :after #'my/test-b) and then (call-interactively 'find-file) I get a "Wrong Number Of Arguments" error again.
TIA.
You can't do that.
Your advice function has to accept the arguments for the original function.
C-hig (elisp)Advice Combinators says:
:after
Call FUNCTION after the old function. Both functions receive the
same arguments, and the return value of the composition is the
return value of the old function. More specifically, the
composition of the two functions behaves like:
(lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
A way to take arbitrary arguments and ignore them is:
(defun foo (&rest _args) ...)
The underscore tells the byte-compiler that the arguments are unused in the function body on purpose.

Dynamic function call in Racket class combined with apply

TL;DR
What I'm looking for is a combination of the functions send/apply and dynamic-send. So that it finds a method of an object based on a symbol and unpacks a list of arguments.
Background and more info
For a project I am sending some "commands" trough the network with Racket's tcp-connect. At the receivers end this command should execute a method from a class and pass along its parameters.
Consider the following received 'message':
(define message (list 'set-switch! '3 'on))
(define method-name (car msg)) ;'set-switch!
(define parameters (cdr msg)) ;(list '3 'on)
And the following class:
(define light%
(class object%
(super-new)
...
(define/public (set-switch! id mode)
(vector-set! switches id mode))))
The problem now is that when executing this statement
(dynamic-send light-class method-name parameters)
it perfectly finds the method set-switch! but it calls it with only one parameter (list '3 'on).
The Racket docs mention those three functions for classes:
(send obj-expr method-id arg) which just executes a method of an object
(send/apply obj-expr method-id arg-list-expr) which executes a method AND unpacks the argument list
(dynamic-send obj method-name v) which finds a method-name based on a symbol
What I think I need is something like (dynamic-send/apply obj method-name arg-list-expr) which combines the last two mentioned.
Note: I know that I could just simply accept lists as parameters and use car and cdr in the functions itself to get the right values. But that's not what I want.
dynamic-send is a function (also known as procedure; e.g., car, vector-set!, +), so you can use apply:
(apply dynamic-send light-class method-name parameters)
Or even simply:
(apply dynamic-send light-class message)
The reason why send has the send/apply variant is that send is a form (also known as syntax; e.g., let, define, if), so apply doesn't work and hence send/apply is separately provided.

call function with two string parameters in Common-LISP Programming

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.

re-internilizing a symbol from namespace-mapped-symbols

I'm not sure if the question title is appropriate but here is what I wonder:
From the repl, I wanted to get the list of bindings defined in the current module. After some searching this seemed like a good solution:
(define (racket-symbols-set)
(list->set (namespace-mapped-symbols (module->namespace 'racket))))
(define (namespace-symbols-set)
(list->set (namespace-mapped-symbols)))
(define (module-bindings)
(set->list (set-subtract
(namespace-symbols-set)
(racket-symbols-set))))
so, calling (module-bindings) returns a list of symbols. But if I try to call a symbol from that result, such as doing ((first (module-bindings))), I get a "application: not a procedure" error although the first symbol is a procedure.
How do I call the corresponding procedure of that symbol?
You can look up the value of a namespace variable using namespace-variable-value. And since your namespace-symbols-set just uses the current namespace, which is also the default namespace for namespace-variable-value, using it is very simple.
For example, to invoke the procedure associated with the first item in the list returned by your module-bindings procedure:
((namespace-variable-value (car (module-bindings))))
Alternatively, specify your preferred namespace as the fourth argument of the namespace-variable-value call.
You need to evaluate that symbol in order for it to return the corresponding procedure.
> (define (foo) 'bar)
> (eval 'foo)
#<procedure:foo>
> ((eval 'foo))
'bar
Hence in your case
((eval (car (module-bindings))))
will call the first procedure of the list returned by module-bindings.

define and assign function call result in racket

I would like to assign the result of a function call (a list) to some var/name.
I tried
(define somelist (call-a-function arg))
but when I do
(display somelist)
it prints #procedure
What is the best way of doing this?
It's a safe bet that this:
(call-a-function arg)
Is returning a function, not a list as you assumed. That's why you're getting a #procedure printed on-screen. Check your function, make sure it returns the appropriate value.

Resources