Hi Tom,
Looks like you've uncovered a bug in mocl's ANSI compatibility. The safest bet is simply to make sure all defining forms (i.e. DEF___, like DEFUN) occur at the top level rather than nesting them within another form. If you need locally scoped functions / closures I would recommend lambda, flet, and/or labels used within the body of a top-level defun form. For example:
(defun tester (string)
(let* ((testlist '(a b c d e f g))
(tester-closure (lambda (s)
(princ-to-string (funcall (intern s) testlist)))))
(rt:formatd "~S" (funcall tester-closure string))))
For what it's worth, this bug can be traced to mocl's lineage to Guy Steele's CLtL, which didn't require defining forms like DEFUN to work outside the top level. Doing so was added under ANSI, but in practice, it is rarely used, and this isn't an area of mocl that is well exercised.
I will try to see that this gets fixed at some point. If it's important and/or urgent for you, let me know.
Wes
- Wukix, 2378 days ago
Thanks for the reply. Again, my LISP is a bit rusty, but it seems the downside to doing it with labels, flet, etc, is that I cannot easily expose multiple procedures in the same closure to the Objective C world without using a dispatching lisp function.
For instance, if i had an init procedure which set up the testlist based on the some user input and the tester which worked on that testlist. I would need tester to have an init mode. Basically, all the calls that want to reference that closure would need to go through a dispatcher.
Is there a better way of doing that?
- tom, 2378 days ago
Is there any reason why you don't just define testlist globally (e.g., with defvar as you already pointed out) and then use setf to modify testlist during init? Are you trying to avoid setf for functional purity?
- Wukix, 2378 days ago
Yes, what you are suggesting will work. I'm exploring and trying to fully understand the integration between the two environments before i kick off the real project.
Also, noticed I cannot send back a lambda into the Objective C environment and then back into lisp to be called. Any plans for that? I expected the Lambda would come into Objective C as an NSObject (which is opaque).
- tom, 2378 days ago
No plans on lambda passing. You could instead pass around some kind of key that refers to lambdas:
(defvar *funs* (make-hash-table :test #'equal)) ; equal is used for string equality
... in init:
(setf (gethash "fun1" *funs*) (lambda () 123))
(setf (gethash "fun2" *funs*) (lambda () 234))
... usage:
(funcall (gethash "fun1" *funs*)) => 123
(funcall (gethash "fun2" *funs*)) => 234
Note that the default hash table printer is ugly and it's useful to define it:
(defmethod print-object ((object hash-table) stream)
(format stream "~<#H(~;~@{~S ~S~^ ~_~}~;)~:>"
(let (l)
(maphash (λ (key value)
(push value l)
(push key l))
object)
l)))
- Wukix, 2378 days ago
Second note: that last λ should be lambda -- I pasted it from my emacs which auto-converts 'lambda' into 'λ'.