Consider this question. Here the basic problem is the code:
(progv '(op arg) '(1+ 1)
(eval '(op arg)))
The problem here is that progv binds the value to the variable as variable's symbol-value not symbol-function. But, that's obvious because we didn't explicitly suggest which values are functions.
The Plan
So, in order to solve this problem, I thought of manually dynamically binding the variables, to their values based on the type of values. If the values are fboundp then they should be bound to the symbol-function of the variable. A restriction, is that match-if can't be a macro. It has to be a function, because it is called by a funcall.
Macro : functioner:
(defmacro functioner (var val)
`(if (and (symbolp ',val)
(fboundp ',val))
(setf (symbol-function ',var) #',val)
(setf ,var ,val)))
Function: match-if:
(defun match-if (pattern input bindings)
(eval `(and (let ,(mapcar #'(lambda (x) (list (car x))) bindings)
(declare (special ,# (mapcar #'car bindings)))
(loop for i in ',bindings
do (eval `(functioner ,(first i) ,(rest i))))
(eval (second (first ,pattern))))
(pat-match (rest ,pattern) ,input ,bindings))))
Here, the let part declares all the variables lexically (supposedly). Then declare declares them special. Then functioner binds the variables and their values aptly. Then the code in the pattern is evaluated. If the code part is true, then only the pattern-matcher function pat-match is invoked.
The Problem
The problem is that in the function, all it's arguments are evaluated. Thus bindings in the let and declare parts will be replaced by something like :
((v1 . val1)(v2 . val2)(v3 . val3))
not
'((v1 . val1)(v2 . val2)(v3 . val3))
So, it's treated as code, not a list.
So, I'm stuck here. And macros won't help me on this one.
Any help appreciated.
Not the answer you are looking for, but PROGV is a special operator; it is granted the ability to modify the dynamic bindings of variables at runtime; AFAIK, you can't simply hack it to operate on "dynamic function bindings".
The point of progv is to use list of symbols and values that are evaluated, meaning that you can generate symbols at runtime and bind them dynamically to the corresponding values.
You might be able to find a solution with eval but note that if you macroexpand into (eval ...), then you loose the surrounding lexical context, which is generally not what you want ("eval" operates on the null lexical environment). I speculate that you could also have a custom code walker which works on top-level forms but reorganizes them, when it finds your special operator, to bring the context back in, producing something like (eval '(let (...) ...)).
Related
Is there a way, in common lisp, to receive a user input, say "foo", and defvar a global variable *foo*?
For example (which does NOT work):
(defun global-name (s)
"Takes s and changes it to *s*"
(concatenate 'string "*" s "*"))
(defun add-global-var (var)
"defvars a global variable and adds it to *global-list*"
(let ((var-name (global-name var)))
(defvar var-name var)
(push var-name *global-list*)))
; Used like this:
(add-global-var "myvar")
In this case, the var-name is a string, and will not work with defvar.
Déjà vu... I asked these kinds of questions 20+ years ago ;-)
Your question
Yes, you can do that (but no, you do not want to!)
(defun add-global-var (var-name &optional (package *package*))
(let ((var (intern var-name package)))
(proclaim `(special ,var))
(push var *global-list*)))
Please see
proclaim
intern
*package*
Alternatively, you can use a macro as the other answer suggests - in
fact, symbol creation at macroexpansion time (which is part of
compilation) is a very common thing,
cf. gensym.
Your problem
There is little reason to do this though.
Global variables created at run time were not available at compile time
and are, therefore, pretty useless.
Why do you want to do this?
If you want to map strings to values, you are much better off using an
equal hash table.
If you want to integrate with read,
you should call it while binding
*package*
to your internal temp package and then use
symbol-value
to store and retrieve values.
You will use intern to
map "variable names" to the symbols.
This is most likely a XY problem since it's very unusual to need to make a variable with a name made up in runtime. It's very common in compile time, but not runtime. #coredump has already covered compile time macros if that is what you are after.
Here is how you do it though:
(defun add-global-var (var)
"defvars a global variable and adds it to *global-list*"
(let ((var-name (intern (string-upcase (global-name var)))))
(set var-name var)
(push var-name *global-list*)))
set is deprecated, but I doubt it will ever be removed. Implementations might not be able to run as fast though since this is like messing with internals.
Since the names are not from source you you have no good use for the bidnings. because of this I would rather use a hash:
(defvar *bindings* (make-hash-table :test #'eq))
(defun add-binding (var)
(let ((var-name (intern (string-upcase (global-name var)))))
(setf (gethash var-name *bindings*) var)
*bindings*))
A reason to do this is as a part of your own little interpreter symbol table or something. You don't need a list of them since you can get all the keys from the hash as well as get the bound values.
Yes, with a macro:
(defvar *global-list* nil)
I changed global-name so that it also accepts symbols, to avoid thinking about whether the string should be upcased or not. With a symbol, the case is given by readtable-case (you can use uninterned symbols if you want to avoid polluting packages).
(defun global-name (name)
(check-type name (or string symbol))
(intern
(concatenate 'string "*" (string name) "*")))
I named the macro defvar*:
(defmacro defvar* (name)
`(push
(defvar ,(global-name name) ',name)
*global-list*))
Tests:
CL-USER> (defvar* #:foo)
(*FOO*)
CL-USER> (defvar* #:bar)
(*BAR* *FOO*)
Note:
You can also add an optional package argument like in #sds's answer, that's better.
I've been trying to write a recursive loop in clojure that will print me out the very last number in the list. The point is not that I need to get the last number (for which I'm sure there's a built in function for that) but that I want to better understand recursion and macros in clojure. So I have this macro...
(defmacro loop-do [the-list]
`(if (= (count '~the-list) 1)
(println (first '~the-list))
(loop-do (rest '~the-list))))
But I get a stackoverflow error. What am I doing wrong?
How will people use your macro?
Somewhere, someone will call:
(loop-do list)
As a piece of code, those are only two symbols in a list. The first one is recognized as your macro, and the second one, list, is a symbol that represents a variable that will be bound at runtime. But your macro only knows that this is a symbol.
The same goes for:
(loop-do (compute-something))
The argument is a form, but you do not want to get the last element of that form, only the last element of the list obtained after evaluating the code.
So: you only know that in your macro, the-list will be bound to an expression that, at runtime, will have to be a list. You cannot use the-list as-if it was a list itself: neither (count 'list) nor (count '(compute-something)) does what you want.
You could expand into (count list) or (count (compute-something)), though, but the result would only be computed at runtime. The job of the macro is only to produce code.
Recursive macros
Macros are not recursive: they expand into recursive calls.
(and a b c)
might expand as:
(let [a0 a] (if a0 a0 (and b c)))
The macroexpansion process is a fixpoint that should terminate, but the macro does not call itself (what would that mean, would you expand the code while defining the macro?). A macro that is "recursive" as-in "expands into recursive invocations" should have a base case where it does not expand into itself (independently of what will, or will not, happen at runtime).
(loop-do x)
... will be replaced by:
(loop-do (rest 'x))
... and that will be expanded again.
That's why the comments say the size actually grows, and that's why you have a stackoverflow error: macroexpansion never finds a fixpoint.
Debugging macros
You have a stackoverflow error. How do you debug that?
Use macroexpand-1, which only performs one pass of macroexpansion:
(macroexpand-1 '(loop-do x))
=> (if (clojure.core/= (clojure.core/count (quote x)) 1)
(clojure.core/println (clojure.core/first (quote x)))
(user/loop-do (clojure.core/rest (quote x))))
You can see that the generated code still contains a call to usr/loop-do , but that the argument is (clojure.core/rest (quote x)). That's the symptom you should be looking for.
So consider the following code:
(define-condition some-condition (error) nil)
(defmethod print-object ((obj some-condition) stream)
(format stream "HELLO THERE"))
(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message)
`(let ((result-message
(handler-case (funcall ,fn-to-cause-error)
(,error-type-to-catch (e) (funcall ,fn-to-handle-error e)))))
(assert (string= result-message
,expected-message))
t))
I can use it like so:
(error-report-test-aux (lambda () (error 'some-condition))
some-condition
#'princ-to-string
"HELLO THERE")
But I wanted to make error-report-test-aux a function instead of macro, so that i can pass to it a type of condition within a variable.
To simply write defun instead of defmacro and remove backquote and commas doesn't work because handler-case is macro and it doesn't evaluate error-type-to-catch.
My question is: Is there something like handler-case that would evaluate it's arguments (specifically condition type argument)?
Yes and no :-)
No to your exact question
There is no standard function that would do what you want because catching errors requires establishing bindings and one usually want to bind constant symbols (like in let/let*) because it is easier to optimize.
You might consider creating a "universal" handler using handler-bind and then declining to handle "uninteresting" conditions (as suggested by #jkiiski in comments), but I am not sure if that fits your exact requirements (untested!):
(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message)
(catch 'trap
(handler-bind ((error
(lambda (condition)
(when (typep condition error-type-to-catch)
(throw 'trap (string= (princ-to-string condition)
expected-message))))))
(funcall fn-to-cause-error))))
Yes, implementation-specific
IF your implementation implements handler-case/handler-bind by binding an internal global variable, you can use progv to bind it yourself and thus implement your error-report-test-aux as a function.
This is probably not the best idea (your code becomes wedded to a specific implementation).
Yes, kinda
You can use the fact that some-condition names a CLOS class and use generic functions instead of the macro.
Why doesn't this work?
( ((lambda () (lambda (x) (funcall #'1+ x)))) 2)
; yields Compile-time error: illegal function call
I ran into a situation like this and it later turned out that a funcall fixes it, i.e.
(funcall ((lambda () (lambda (x) (funcall #'1+ x)))) 2) ; => 3
I'm confused because it seems like the first one should work, because I actually have a function I'm calling, not just a symbol that may belong to either namespace (i.e. (type-of ((lambda () #'1+))) ; => FUNCTION). I thought it would be kind of like how you don't need to funcall a lambda for example, e.g.((lambda (x) x) :HI) ; => :HI. What am I missing?
Common Lisp uses the word form for everything which can be evaluated.
A form is either
a symbol like foo
a compound form, a list, see below
or a self-evaluating object (like numbers, characters, arrays, strings, ...).
A compound form is either
a special form (<special-operator> ...)
a lambda form like (lambda (...) ...)
a macro form (<macroname> ...)
or a function form (<functionname> ...).
Above is the set of compound forms. The ANSI Common Lisp specification provides no way to add a new type of forms or a different syntax. The interface of what forms the functions like EVAL or COMPILE accept is not extensible.
So something like
(((lambda (foo)
(lambda (bar)
(list foo bar)))
1)
2)
is not valid Common Lisp. This is not meaningful in Common Lisp:
( <not a lambda form,
not a special operator,
not a macro name
and not a function name>
2)
Note that Common Lisp allows lambda forms, special operators, macro names and function names as the first element in a compound form. But it does not allow variables and it does not allow other compound forms as the first element in a compound form.
Means this is not meaningful in Common Lisp:
( <a function form> 2)
Thus ((foo 1) 2) or (((foo 1) 2) 3) or ((((foo 1) 2) 3) 4) or (((((foo 1) 2) 3) 4) 5) is not legal in Common Lisp. You get the idea. To call function objects returned from function calls, we have to use (funcall (foo ...) ...). This makes calling returned function objects more obvious than just ((foo ...) ...).
Let's praise the designers of Common Lisp for this feature. Otherwise I might have to look at possibly meaningful code beginning with
(((((((((((( .....
and it would be very hard to figure out what it does. Basically that would be write-only code.
Your question:
Why must I funcall a function returned from another?
The short answer: because the syntax does not allow other ways, in Common Lisp.
The syntax of Common Lisp requires that, everytime you want to call a function through a compund form of the type:
(f a1 a2 ... an)
the first element of the list, f, must be a symbol denoting a function name, or a list denoting a lambda expression, i.e. (see the manual):
lambda expression n. a list which can be used in place of a function name in certain contexts to denote a function by directly describing its behavior rather than indirectly by referring to the name of an established function; its name derives from the fact that its first element is the symbol lambda.
So, this basically means that you cannot have as first element any expression that returns a function as value. In those cases, you must use funcall.
So, in your second example, the first argument of the funcall is ((lambda () (lambda (x) (funcall #'1+ x)))), which is a correct coumpound form, in which the first element of the list is the lambda expression (lambda () (lambda (x) (funcall #'1+ x))) (applied to an empty list of arguments).
In the first example, instead, you have as first element of the list an expression returning a function, so that you must use funcall.
I have read this article and then modified my code below:
(defparameter *my-fun* 1)
(defun my-func (v0)
(setf (symbol-function '*my-fun*)
(lambda (v1)
(+ v0 v1)))
'*my-fun*)
And call it in this way ((my-func 2) 3),but it also report "illegal function call". I think my code is keeping with lambda calculus,but where is wrong.
In my opinion, (my-func 2) returns symbol *my_fun*, and the function cell of *my-fun* points to a function object, so ((my-func 2) 3) => (*my-fun* 3) => ((lambda (v1) (+ 2 v1)) 3) => (+ 2 3) => 5
This works: First your identical definitions:
(defparameter *my-fun* 1)
(defun my-func (v0)
(setf (symbol-function '*my-fun*)
(lambda (v1)
(+ v0 v1)))
'*my-fun*)
However, invoke using funcall:
(funcall (my-func 2) 3)
I am confused about the &environment parameter in common lisp. In particular, what is it useful for, and why is it a parameter, rather than a special variable?
EDIT: It would also be nice to see a concrete example of how &environment would be used in code.
Doc
Macro Lambda Lists:
&environment is followed by a single variable that is bound to an
environment representing the lexical environment in which the macro
call is to be interpreted. This environment should be used with
macro-function, get-setf-expansion, compiler-macro-function, and
macroexpand (for example) in computing the expansion of the macro, to
ensure that any lexical bindings or definitions established in the
compilation environment are taken into account.
Explanation
Operators which define macros (local or global) have to define how code is expanded before being evaluation or compiled, and thus may need to expand existing macros, whose expansion may depend on the environment - so the macro definitions need the environment.
Not a Special Variable
Special variables are more dangerous because the user might rebind them and because they are harder to handle correctly in multi-threaded code.
Example
All over the places.lisp:
(defmacro psetf (&whole whole-form
&rest args &environment env)
(labels ((recurse (args)
(multiple-value-bind (temps subforms stores setterform getterform)
(get-setf-expansion (car args) env)
(declare (ignore getterform))
(when (atom (cdr args))
(error-of-type 'source-program-error
:form whole-form
:detail whole-form
(TEXT "~S called with an odd number of arguments: ~S")
'psetf whole-form))
(wrap-let* (mapcar #'list temps subforms)
`(MULTIPLE-VALUE-BIND ,stores ,(second args)
,#(when (cddr args) (list (recurse (cddr args))))
,#(devalue-form setterform))))))
(when args `(,#(recurse args) NIL))))
From iolib/src/new-cl/definitions.lisp:
(defmacro defconstant (name value &optional documentation
&environment env)
(destructuring-bind (name &key (test ''eql))
(alexandria:ensure-list name)
(macroexpand-1
`(alexandria:define-constant ,name ,value
:test ,test
,#(when documentation `(:documentation ,documentation)))
env)))
For example when Lisp wants to macroexpand a form, it needs to know which name refers to what macro definition. This can depend on the globally available macros, locally bound macros via macrolet or what is available during compilation. Thus the environment object makes it possible to macroexpand a form with respect to different environments.
Environment variables provide to the macro author information about the declarations et. al. enforce when the macro was invoked. The macro author can then use that information to customize how he chooses to expand the macro. For example he might add or subtract debugging code based on declarations he finds in the environment. For example he might infer the type of expressions he was given to work with and add or subtract code to get better performance.
You can write a lot of Common Lisp code and never use &environment. There are situations where it becomes necessary, when those are would make good follow up question. Rainer hints at an answer to that.