Using custom function getter as setter with setf - lisp

I think it is apparent from this code what I'm trying to do, that is, change 'blue to 'purple:
CL-USER> (defparameter myassoc '((color red blue) (shape circle square)))
MYASSOC
CL-USER> myassoc
((COLOR RED BLUE) (SHAPE CIRCLE SQUARE))
CL-USER> (defun getsecondof (assoc) (second (rest (assoc assoc myassoc))))
GETSECONDOF
CL-USER> (getsecondof 'color)
BLUE
CL-USER> (setf (getsecondof 'color) 'purple)
; in: SETF (GETSECONDOF 'COLOR)
; (FUNCALL #'(SETF GETSECONDOF) #:NEW954 'COLOR)
; ==>
; (SB-C::%FUNCALL #'(SETF GETSECONDOF) #:NEW954 'COLOR)
;
; caught STYLE-WARNING:
; undefined function: (SETF GETSECONDOF)
;
Now, if instead of using my own function getsecondof with setf I instead pass a built-in CL expression to extract the location I want to change, it works.
Is it possible to use custom getters as setters with setf?

You need to define a setf for it:
(defun (setf getsecondof) (assoc value)
(setf (caddr (assoc assoc myassoc)) value)) ; (caddr x) == (second (rest x))
(setf (getsecondof 'color) 'purple) ; ==> PURPLE
(getsecondof 'color) ; ==> PURPLE

You have do define a setf function.
http://www.lispworks.com/documentation/HyperSpec/Body/m_defset.htm#defsetf

Related

Make `define` evaluate its first argument in Racket

In some dialects of LISP, there is a distinction between SET and SETQ, the first one evaluates its first argument so that you need to use the (SET (QUOTE …) …) syntax.
Since in Racket, quoting is not needed in definitions, define behaves as SETQ.
Is there a Racket function that behaves like SET? If no, how to write one?
I tried (define (SET a b) (define (eval a) b) b) but it does not seem to work when providing it to an other language with (provide SET).
Here's my quick attempt at this problem:
;; lib.rkt
#lang racket/base
(provide (rename-out [#set set]
[##%top #%top]
[#set! set!]
[#define define]))
(require syntax/parse/define)
(define env (make-hash))
(define (set x v stx)
(unless (hash-has-key? env x)
(raise-syntax-error #f "undefined id" stx))
(hash-set! env x v))
(define-simple-macro (##%top . x)
(hash-ref
env
'x
(λ () (raise-syntax-error #f "unbound id" (quote-syntax x)))))
(define (#set x v)
(set x v x))
(define-simple-macro (#set! x:id v)
(set 'x v (quote-syntax x)))
(define-simple-macro (#define x:id v)
(begin
(when (hash-has-key? env 'x)
(raise-syntax-error #f "id already defined" (quote-syntax x)))
(hash-set! env 'x v)))
#lang racket/base
(require "lib.rkt")
(define x 1)
(set (if #t 'x 'y) 2)
(add1 x) ; 3
(set! x 3)
(add1 x) ; 4
(add1 y) ; y: unbound id in: y
Note that this differs from original Racket in several ways. For example:
unbound ids are now reported at runtime instead of compile-time.
set! now won't work with set!-transformer.
define can't be used to define functions
define can't be used to shadow an identifier.
For (2) and (3), it's possible to get the original behavior back, but I don't want the answer to be too long, so I didn't include the full functionality. For now, I don't know how to solve (4).
Also note that you can only set identifiers defined via define. If you want to set identifiers defined via lambda, let, etc., you need to redefine these constructs too.
I would do it much less verbose and much simpler.
Since all arguments are evaluated, the set or let's say define% can be defined as a function!
(define (define% x y)
(eval `(define ,x ,y)))
One can even define functions using define% when using old-style form using lambda.
(define 'ab (lambda (x y) (+ x y)))
(ab 3 5) ;; 7
It even behaves correctly in terms of scope
(define (foo x)
(define% 'bar (lambda (x) (+ 1 x)))
(bar (bar (bar x))))
foo
;; #<procedure:foo>
bar
; bar: undefined;
; cannot reference undefined identifier
; [,bt for context]
(foo 3)
6
;; after first call however, bar is available in global environment
;; as pointed out by #AlexKnauf
bar
;; #<procedure:bar>
Thus there are some scoping issues ...
(let ((x 0))
(define% 'counter (lambda () (set! x (+ x 1)) x)))
counter
;; #<procedure>
(counter)
;; 1
(counter)
;; 2
(counter)
;; 3

Build dynamic COND clauses in Common Lisp

I wonder if it is possible to dynamically build COND clauses from a loop like (pseudo code):
(defvar current-state 1)
(defmacro mymacro ()
(cond
`(loop (state . callback) in possible-states
do ((eq current-state ,state)
(funcall ,callback)))))
The LOOP would build the clauses from a list and generate something like:
(cond
((eq current-state 1)
(funcall func-1))
((eq current-state 2)
(funcall func-2))
((eq current-state 3)
(funcall func-3)))
Macros are expanded at compile time, so your possible-states variable has to be a compile-time constant. If this is not the case (or if you are not absolutely clear on what I mean above), you should not use a macro here.
Use a function instead:
(funcall (cdr (find current-state possible-states :key #'car :test #'eq)))
or
(funcall (cdr (assoc current-state possible-states :test #'eq)))
or, better yet, make your possible-states a hash
table rather than an association
list:
(funcall (gethash current-state possible-states))
However, if your possible-states is a compile time constant, you
can, indeed, use a macro, except that you probably want to use
case instead of
cond:
(defmacro state-dispatch (state)
`(case ,state
,#(mapcar (lambda (cell)
`((,(car cell)) (,(cdr cell))))
possible-states)))
(defparameter possible-states '((1 . foo) (2 . bar)))
(macroexpand-1 '(state-dispatch mystate))
==> (CASE MYSTATE ((1) (FOO)) ((2) (BAR))) ; T
Note that from the speed point of view, the gethash version is probably identical to the macro version (at the very least it is not slower).

How to pass lexical bindings of functions to 'eval' in Emacs Lisp?

In Emacs Lisp, lexical environment are represented by an alist, mapping symbols to their value. It can be passed to evaluators as a second argument of 'eval' function.
(eval '(+ 3 var)
'((var . 4)))
→ 7
However, I can't figure out how to pass functions, not variables,
to the evaluator.
For example, either of the following expressions shows an error.
(eval '(func 3)
'((func . (lambda (x) (+ 4 x)))))
→ error: (void-function func)
(eval '(func 3)
'((func . (closure (t) (x) (+ 4 x)))))
→ error: (void-function func)
Any help is appreciated.
How about this :
(eval '(apply func (list 3))
'((func . (lambda (x) (+ 4 x)))))
Here's how you can do it:
(defun my-eval (exp var-bindings fun-bindings)
(eval `(cl-flet ,(mapcar (lambda (x) (list (car x) `',(cdr x)))
fun-bindings)
(let ,(mapcar (lambda (x) (list (car x) `',(cdr x)))
var-bindings)
,exp))
t))
or, using eval's builtin support for var-bindings:
(defun my-eval (exp var-bindings fun-bindings)
(eval `(cl-flet ,(mapcar (lambda (x) (list (car x) `',(cdr x)))
fun-bindings)
,exp)
(or var-bindings t)))
[ BTW, note that it is not always true that in Emacs Lisp, lexical environment are represented by an alist: after byte-compilation, lexical variables don't have any name any more, they're stored on "the" stack and they're directly accessed via their position in the stack. ]

Common Lisp: Use undefined variable in function

I want to do something like that in Common Lisp:
(defparameter *fun*
(lambda () x))
(let ((x 0))
(funcall *fun*)) ;should return 0
I want to access a local binding in a function, that is not defined, when I define the function.
If I use x as parameter, it would work, but I can't change the value of the variable:
(defparameter *fun*
(lambda (x) (setf x (+ x 1))))
(let ((x 0))
(funcall *fun* x)) ;should return 1, would return 0
How can I do what I want?
You can declare the variable special (dynamic) at both the binding site and the reference site:
(defparameter *fun*
(lambda () (declare (special x)) x))
(let ((x 0))
(declare (special x))
(funcall *fun*))
Or globally:
(defvar *x*) ;; makes *x* special
(defparameter *fun*
(lambda () *x*))
(let ((*x* 0))
(funcall *fun*))
Late edit:
A macro might serve you better in this scenario. The only lexical bindings a function can access are the ones that were present when it was created. For example, the behavior you described is given by the standard in the macro incf. Define-modify-macro is a helper for defining macros similar to incf. http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_2.htm
You can define the function in the nested scope:
[2]> (defparameter *fun* (let ((x 0)) (lambda () (setf x (+ x 1)))))
*FUN*
[3]> (funcall *fun*)
1
[4]> (funcall *fun*)
2
If your function is defined outside the scope of a lexical variable, it can't access that variable, by definition of what is lexical scope. To be able to do that, it must be inside that scope.
The other way around this issue is to make the variable special, giving it dynamic extent:
[5]> (defparameter *x* 1)
*X*
[11]> (defun fun () (setf *x* (+ *x* 1)))
FUN
[12]> *x*
1
[13]> (fun)
2
[16]> *x*
2

Increment several variables at once, using &rest?

I would like to create a function that allows to:
(incf vara varb varc vard)
Instead of
(incf vara)
(incf varb)
(incf varc)
(incf vard)
What I do not understand is how to be able to send more arguments, how to define that in a function?
(defun inc (&rest arg)
(interactive)
(mapcar 'incf arg)
)
This increases the argument, but ofcourse does not save them back into the variables.
How to go about this?
If you want to be able to write this form as (my-incf a b c) without quoting the variable names a, b, and c, make it a macro rather than a function:
(defmacro incf+ (&rest vars)
`(progn
,#(mapcar (lambda (var) `(incf ,var)) vars)))
Check that it expands into the right code using macroexpand:
(macroexpand '(incf+ var1 var2 var3))
;; => (progn (incf var1) (incf var2) (incf var3))
Because variables in Emacs Lisp have dynamic scope by default, you can accomplish almost the same thing with a function which takes quoted variable names as arguments. But the macro version has the advantage that, since it expands into code in the place when it was called, it will work with lexically bound variables as well. symbol-value only works with dynamically bound variables.
You can test this by putting the following in a file and loading it (in Emacs 24 or higher):
;; -*- lexical-binding: t -*-
(defun incf+fun (&rest vars)
(mapc #'(lambda (var) (incf (symbol-value var))) vars))
(defun incf-macro-test ()
(let ((a 5) (b 7) (c 11))
(incf+ a b c)
(list a b c)))
(defun incf-function-test ()
(let ((a 5) (b 7) (c 11))
(incf+fun 'a 'b 'c)
(list a b c)))
Evaluating (incf-macro-test) will return (6 8 12), but (incf-function-test) will enter the debugger with a (void-variable a) error.
It should work:
(require 'cl)
(setq a 1)
(setq b 2)
(defun inc (&rest arg)
(interactive)
(mapc (lambda (x) (incf (symbol-value x))) arg))
(inc 'a 'b)
(message "%s %s" a b) => (2 3)
You have to quote each argument otherwise (inc a b) becomes (inc 1 2) before executing inc.