Intercept and modify user input in Common Lisp - reflection

I defined an evaluator in common lisp that can simply be called like:
(repl)
From then on, the repl can interpret function calls like (.cos arg) that are otherwise unknown to lisp.
Ofcourse, to use it, one has to call (repl) first, or lisp doesn't know what .cos is.
I would like to be able to simply call (.cos 90) though, and have it run in the repl. Is there anyway to use lisp's reflection to intercept all user input and call another function before it?
Thanks!

The better way would be to make my-eval, then you can do
(defun my-cos (arg)
(my-eval (list '.cos arg)))
repl would be something like
(defun my-repl ()
(my-eval '((lambda (ev)
(ev ev))
(lambda (ev)
(print (eval (read)))
(ev ev)))))
I assume you have print, eval and read defined in your evaluators null environment.

Related

Good example of when to muffle warnings?

This question is somewhat related to an earlier one on programmatically generating symbol macros. I'm using that function in a convenience macro that throws undefined variable warnings. This macro and function:
(defmacro define-data (d body &optional doc)
(if (and doc (not (stringp doc))) (error "Documentation is not a string"))
`(let* ((d-str (string ',d))
(old-package *package*)
(*package* (if (find-package d-str) ;exists?
(find-package d-str) ;yes, return it
(make-package d-str)))) ;no, make it
;; Should we have an eval-when (:compile-toplevel) here?
(defparameter ,d ,body ,doc)
(export ',d old-package)
(define-column-names ,d)))
(defun define-column-names (d)
(maphash #'(lambda (key index)
(eval `(cl:define-symbol-macro ,key (cl:aref (columns ,d) ,index))))
(ordered-keys-table (slot-value d 'ordered-keys))))
are intended to be like defparameter, but additionally set up a few niceties for the user by defining:
a package with the name of d
a parameter in the current package with the data that will be sucked in by body
symbol-macros in package d for access to the individual data vectors
If I use defparameter from the REPL, and then call define-column-names, all is well. However when using the macro I get:
; in: DEFINE-COLUMN-NAMES FOO
; (DEFINE-COLUMN-NAMES CL-USER::FOO)
;
; caught WARNING:
; undefined variable: CL-USER::FOO
I suspect that this is because the compiler has no way of knowing that FOO will actually be defined when define-symbol-macro is called. Everything works fine, but I don't want the warning to frighten users, so am thinking of suppressing it. I hate suppressing warnings though, so thought I'd come here for a second opinion.
EDIT: I've marked an answer correct because it does correctly answer the question as asked. For an answer to the problem see my comments.
My answer to the 'when to muffle warnings' question in the title is: if it's your own code then never, under any circumstances. If it is someone else's code, then rewrite it not to warn unless you can't.
As to solving the problem I haven't thought about this hard enough, but the problem is that you definitely want the defparameter to be at top-level so the compiler can see it, and it can't really be if it's inside a let. But you can raise it to toplevel trivially since it depends on nothing inside the let.
I am then pretty certain that you want the rest of the macro to happen at compile time, because you definitely want the symbol-macros available at compile-time. So an attempt at the first macro would be (note I've fixed the handling of the docstring: (defparameter foo 1 nil) is bad):
(defmacro define-data (d body &optional doc)
(when (and doc (not (stringp doc)))
(error "Documentation is not a string"))
`(progn
(defparameter ,d ,body ,#(if doc (list doc) '()))
(eval-when (:compile-toplevel :load-toplevel :execute)
(let* ((d-str (string ',d))
(old-package *package*)
(*package* (if (find-package d-str) ;exists?
(find-package d-str) ;yes, return it
(make-package d-str)))) ;no, make it
(export ',d old-package)
(define-column-names ,d)))))
As a side note: although I think the fact that programmatically defining symbol macros is hard because CL left that out for some reason, I think I'd personally use some other approach rather than this, because eval is just so horrid. That's just me however: if you want to do this you do need eval I think (it is very rare that this is true!).
I am not sure exactly how define-columns-names works so I replaced it with a stub function that returns d.
Note also that you can use check-type and should try not injecting symbols in generated code, this introduces potential variable capture that can be avoided with gensym.
As far as I know you cannot use eval-when as suggested by your comment (see Issue EVAL-WHEN-NON-TOP-LEVEL Writeup for details).
But I have no warning if I declare the symbol as being special around the call.
(defmacro define-data (d body &optional doc)
(check-type doc (or null string))
(check-type d symbol)
(let ((d-str (string d)))
(alexandria:with-gensyms (old-package)
`(let* ((,old-package *package*)
(*package* (if (find-package ,d-str) ;exists?
(find-package ,d-str) ;yes, return it
(make-package ,d-str)))) ;no, make it
(defparameter ,d ,body ,doc)
(export ',d ,old-package)
(locally (declare (special ,d))
(define-column-names ,d))))))
It is also a bit strange that you expand into a call to define-column-names, which in turns evaluated a form built at runtime. I think it might be possible to do all you want during macroexpansion time, but as said earlier what you are trying to do is a bit unclear to me. What I have in mind is to replace define-column-names by:
,#(expand-column-names-macros d)
... where expand-column-names-macros builds a list of define-symbol-macro forms.

Neither a function nor a macro would do

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 (...) ...)).

HANDLER-CASE alternative which is not a macro

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.

Accessing structure fields from the structure itself in Common LISP

For my project, I specifically need a structure that has (among other things) 2 slots:
one holds data (current-state, a structure)
one holds a function (is-state-a-solution)
That function slot must evaluate the current-state and return a result based on it. However, I can't find how to do this properly. Here's a segment of my code.
(defstruct state moves-left)
(defstruct problem
(current-state)
(solution (function (lambda () (null (state-moves-left :current-state)))))
)
No errors on compiling, but they happen when I interpret this:
> (setq p0 (make-problem :current-state (make-state)))
> (funcall (problem-solution p0))
SYSTEM::%STRUCTURE-REF: :CURRENT-STATE is not a structure of type STATE
Anyone knows how to solve this? I usually just use common functions, but these structure and slots are hard requirements.
EDIT: thanks for the answers. After learning this was impossible, I reread the requirements more thoroughly and posted the answer here.
You could have a separate create function:
(defun create-problem (state)
(let ((problem (make-problem :current-state state)))
(setf (problem-solution problem)
(lambda ()
(null (state-moves-left (problem-current-state problem)))))
problem))
But: Why not use a function/method directly?
(defmethod problem-solution ((p problem))
(null (state-moves-left (problem-current-state p))))
The reason for the error is that structures in Common Lisp cannot be used as classes: inside the function default value of the slot solution there is no way of referring to the slots of the structure itself (as you are trying to do with (state-moves-left :current-state).
If you insist in using structures instead of classes, one possibility is to define the function with a parameter, and pass the structure itself when the function is called. Something like:
(defstruct problem
(current-state)
(solution (function (lambda (p) (null (state-moves-left p))))))
(let ((p0 (make-problem :current-state (make-state))))
(funcall (problem-solution p0) p0))
After learning this was impossible, I reread the requirements more thoroughly and found out this function will actually receive an argument (a state). So, the code now works:
(defstruct problem
(current-state)
(solution (function (lambda (state) (not (null (state-moves-left state))))))
)

Unbound variable in Common Lisp

I'm new to Lisp and I was reading about an text-generator example in ANSI Common Lisp, Chapter 8. I follow the example and defined a function "see" in the scope of a LET variable "prec",
(let ((prec '|.|))
(defun see (symb)
(let ((pair (assoc symb (gethash prev *words*))))
(if (null pair)
(push (cons symb 1) (gethash prev *words*))
(incf (cdr pair))))
(setf prev symb)))
and saved it into a lisp file.
Then when I returned to REPL and tried to invoke see after loading the compiled version of the file, an error occurred:
The variable PREV is unbound.
[Condition of type UNBOUND-VARIABLE]
How do I invoke see properly? And what's a lexical closure for? I'm all confused.
Thanks for helping.
Looks like you've typed prec instead of prev in the enclosing let form.
Lexical closures are functions that 'close over' a part of the lexical environment (hence the name). There are many good introductions to closures in lisp that I will not attempt to repeat here but, essentially, let is the most common way to manipulate the lexical environment; in this case, you want to add the binding for prev, which will then be available to code within the body of the form. Your function see will 'close over' this binding, and so each call to see has access to it, even though when you make these calls, you will no longer be in the lexical environment established by the let form. You could say the function definition takes the binding with it, in a sense.
As you appear to have mis-typed the name of the prev, your function is trying to refer to a binding that has not been established at that point in the code.

Resources