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.
Related
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.
I wonder if it is possible to tell FORMAT to ignore undefined format directives. I have looked at the pages for FORMAT in the CLHS but I don't see anything.
What I am trying to do is to get FORMAT to ignore ~m in a format string and just output ~m instead of trying to replace it with something. My plan is that at that point I will call another function which knows what to do with with ~m.
I guess a related question is then, is there a way to define a function to handle a format directive which is otherwise not defined?
In anticipation of some questions. (1) I guess a workaround would be to substitute a placeholder for ~m, and then substitute it back in afterwards and keep going. I guess I'll do that if all else fails. (2) I guess another general strategy would be to call the other function first, to handle ~m, then call FORMAT on the result. Unfortunately that other function recognizes some of the same directives, and barfs on others; it doesn't recognize only ~m and ignore everything else.
You can define your own format directive with ~/name/, where name is the name of the function which is called. In your case you would have:
(format t "~/m/" 1)
(defun m (stream n colon-mod at-mod)
(format stream "~a" n)) ; or do something else with n
You still need to change the control string, but you can add a preprocessing step where "~m" is replaced by "~/m/".
I don't think there is a way of doing that portably (implementations may let you do all sorts of magic). I'd write a quote-weird-tildes and dequote-weird-tildes pair of functions and then write code like:
(defun format/qw (control &rest args)
(declare (dynamic-extent args)
(type string control)) ;can't be a function
(dequote-weird-tildes
(apply #'format nil (quote-weird-tildes control) args)))
Now you have a function which looks like (format nil ...) and is no harder to use than that. For extra value the quoting and dequoting functions should not cons a string if they don't have to.
From http://www.lispworks.com/documentation/lw50/CLHS/Body/22_c.htm
The control-string argument to format is actually a format control.
That is, it can be either a format string or a function, for example a
function returned by the formatter macro.
So you can do:
(defmacro frmt (control-string)
(let ((str (cl-ppcre:regex-replace-all "~m" control-string "~~m")))
`(formatter ,str)))
Now:
(format t (frmt "~m~A") 1)
outputs:
~m1
NIL
This way you don't have to modify the control string directly.
You do have to modify the call to format to include frmt.
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.
Can anyone briefly explain to me how message passing is implemented in scheme? I think I am little off on the whole concept of message passing.
Take a look at SICP.
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-17.html#%_sec_2.4.1
http://www.michaelharrison.ws/weblog/?p=50
Message passing in the context of closures
The following example defines a closure implementing a simple calculator. The function make-calculator is similar to what object oriented languages call the constructor. The difference is: make-calculator returns a function, while constructors return object values. In object oriented languages object values are first class values. Scheme does not have such values. An object first class values provides the functionality to access object member variables and object methods. In Scheme this functionality has to be emulated by the definition of a dispatch function. make-calculator returns such a function. The body of make-calculator defines
two variables a and b (member variables)
two mutation functions set-a! and set-b! (accessors)
four evaluation functions addition, subtraction, multiplication and division (methods)
The above definitions are local to the closure make-calculator. In an object oriented language they are called private. The dispatch function makes the functions public and keeps the variables private. This works, because the dispatch function has access to the local scope of the make-calculator closure. The dispatch function accepts a message and returns the matching function. This exposes the local functions to the caller of the dispatch function.
(define (make-calculator)
(define a)
(define b)
(define (set-a! value)
(set! a value))
(define (set-b! value)
(set! b value))
(define (addition)
(+ a b))
(define (subtraction)
(- a b))
(define (multiplication)
(* a b))
(define (division)
(/ a b))
(lambda (message)
(case message
((set-a!) set-a!)
((set-b!) set-b!)
((addition) addition)
((subtraction) subtraction)
((multiplication) multiplication)
((division) division))))
First the constructor has to be called to create an "object". calc is the dispatch function, which accepts different messages, which are just symbols.
(define calc (make-calculator))
Sending a message means calling the dispatch function with a symbol argument. The following sends the message set-a! to calc, which returns the value of the local function set-a!. The name of the message and the name of the local function are the same in this case. This helps to avoid confusion, but it is not required.
(calc 'set-a!) ;; => #<procedure set-a!>
Because calc returns a function, an additional application is necessary to call the accessor. The following sets a to 3 and b to 5.
((calc 'set-a!) 3)
((calc 'set-b!) 5)
Now we can calculate:
((calc 'addition)) ;; => 8
((calc 'subtraction)) ;; => -2
((calc 'multiplication)) ;; => 15
((calc 'division)) ;; => 3/15
The code works this way in Chez Scheme.
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")