From the things I have read I understand that Accessor functions in CLOS allows for the programmer to get and set variables and it generates a generic function of the name that was give in to the accessor to which you need to define different methods.But I what I want to know is why Don't generic functions work the same way as the accessor functions?
for example
(defclass animal ()
((sound
:initarg :sound
:initform "no sound"
:accessor make-sound)))
I can just
define
(defmethod (setf make-sound) ((the-animal animal) value)
(setf (slot-value the-animal 'sound) value))
but if i were to take the accessor away and add in
(defgeneric (setf make-sound) (the-animal value))
then I get an error when after executing the following code.
(setf (make-sound dog) "bark")
unless I redefine the generic function and method as the following
(defgeneric (setf make-sound) (value the-animal))
(defmethod (setf make-sound) (value (the-animal animal))
(setf (slot-value the-animal 'sound) value))
or execute
(setf (make-sound "bark") dog) ;this also works with the accessor
My question is why is this happening?Why can't I achieve the same result with generic functions?
A defmethod form creates a generic function if there isn't one.
CL-USER 7 > (defclass animal ()
((sound
:initarg :sound
:initform "no sound")))
#<STANDARD-CLASS ANIMAL 40200ED09B>
Remember: the new value comes first in a SETF function. That's defined by the Common Lisp standard.
CL-USER 8 > (defmethod (setf make-sound) (value (the-animal animal))
(setf (slot-value the-animal 'sound) value))
#<STANDARD-METHOD (SETF MAKE-SOUND) NIL (T ANIMAL) 40200F098B>
CL-USER 9 > (let ((dog (make-instance 'animal)))
(setf (make-sound dog) "bark")
dog)
#<ANIMAL 402002187B>
CL-USER 10 > (slot-value * 'sound)
"bark"
Seems to work.
In defclass the :accessor slot option defines that it defines a reader method and also a corresponding setf method with the correct parameter list: new value first, then the instance of that class.
Related
why under dynamic scope this code will return error for "g not defined"?
when running ((ff) 5), at some point g will get a value (the f lambda) and will be inserted into the runtime stack.
(
let ((f (lambda (g)
(lambda (n)
(if (zero? n)
1
(* n ((g g) (- n 1))))))))
((f f) 5)
)
With dynamic scope you don't have closures. Eg.
(define val #f)
(define (get-val val)
(lambda ()
val))
(define getter (get-val 5))
(getter) ; => #f
With lexical scope val from get-val lives in the returned procedure as a free variable and would return 5, but in dynamic scope it stopped existing right ather the proceudre was returned. The val referred in the procedure is whatever bound val in the dynamic scope. Eg.
(let ((val 10))
(getter)) ; ==> 10
So val from the let became the closest binding with that name ad getter returned that.
I would like to make this function to set keybind more shorter.
(defun defkey-arg2 ()
(exwm-input-set-key (kbd "s-g")
(lambda ()
(interactive)
(start-process-shell-command gkamus nil gkamus))))
then I write the shorter function with 2 parameters (the keybind and the app name)
(defun defkey-arg2 (key command) (...)
When I try the key as parameter, it will work
(defun defkey-arg2 (key)
(exwm-input-set-key (kbd key)
(lambda ()
(interactive)
(start-process-shell-command gkamus nil gkamus))))
(defkey-arg2 "s-g")
But, when I try write function like this
(defun defkey-arg2 (key command)
or
(defun defkey-arg2 (command)
(exwm-input-set-key (kbd "s-g")
(lambda ()
(interactive)
(start-process-shell-command command nil command)))
(defkey-arg2 "gkamus")
it raises error:
Symbol's value as variable is void:' when using parameter on defun
The body of lambda isn't evaluated. Using a backquote, the value of command can be substituted into the resulting expression.
(defun defkey-arg2 (command)
(define-key (current-local-map)
(kbd "s-g")
`(lambda ()
(interactive)
(start-process-shell-command ,command nil ,command))))
I'd like to define methods on class objects, that inherit based upon the class' ancestry in the same way that instances' methods inherit. Is there some way to do this?
Here's what's not working: eql-method specialization. Consider this example:
(defclass animal ()())
(defclass bird (animal)())
(defclass woodpecker (bird)())
(defmethod wings-p ((animal-class (eql (find-class 'animal)))) nil)
(defmethod wings-p ((bird-class (eql (find-class 'bird)))) t)
Calling (wings-p (find-class 'woodpecker)) generates a no-method-error, and you can see why - class woodpecker obviously isn't eql to any method specializers.
I'd like to define "methods" on bird and animal so that when I call wings-p on (find-class woodpecker), wings-p returns t.
I feel like this is a standard feature of nearly every other OO system, but I can't remember how to do it with CLOS.
There is indeed no direct inheritance link among objects returned by (find-class 'bird) and (find-class 'woodpecker), exactly as you cannot expect a generic function specialized only on (eql 1) and (eql 2) to produce a result when given a value of 3.
In your case you could derive metaclasses from STANDARD-CLASS.
You would need to define methods for VALIDATE-SUPERCLASS too and then you could define your own class having the appropriate :metaclass parameter. For example (find-class 'animal) would return an instance of animal-class.
Then, instead of specializing on (eql (find-class 'animal)) you would specialize on animal-class. More precisely:
(defpackage :meta-zoo (:use :closer-common-lisp))
(in-package :meta-zoo)
(defclass animal-class (standard-class) ())
(defclass bird-class (animal-class) ())
(defclass woodpecker-class (bird-class) ())
(defmethod validate-superclass ((class animal-class)
(super standard-class)) t)
(defclass animal () () (:metaclass animal-class))
(defclass bird () () (:metaclass bird-class))
(defclass woodpecker () () (:metaclass woodpecker-class))
(defgeneric class-wing-p (class)
(:method ((a animal-class)) nil)
(:method ((b bird-class)) t))
(defparameter *woody* (make-instance 'woodpecker))
(class-of *woody*)
;; => #<woodpecker-class woodpecker>
(class-wing-p (class-of *woody*))
;; => t
Could someone please clarify the concepts behind this use of the "this" keyword?
(define call
(lambda (obj method-name . args)
(apply (obj method-name) obj args)))
(define -cuboid-
(lambda (w l h)
(define volume
(lambda (this)
(* h (call this 'area))))
(define area
(lambda (this)
(* w l)))
(lambda (method-name)
(cond
((eq? 'volume method-name) volume)
((eq? 'area method-name) area)
(else (error "method not found: ~s" method-name))))
(define r1 (-cuboid- 2 3 4))
(call r1 'area) ;=> 6
(call r1 'volume) ;=> 24
I understand that this is a keyword to refer to the object that is being used. I found out that this alone doesn't have any particular meaning in this program (it needs to refer to the arguments of the lambda functions).
The call is ((-cuboid- 2 3 4) 'volume), which brings to (* h (call this 'area)), where has this been defined?
this is simply the argument of the lambda, this could be anything; try changing it to, e.g., myself in the first lambda and me in the second (where it is not used, by the way, but needs to be there for the call to work).
The call to ((-cuboid- 2 3 4) 'volume) returns that procedure, with names bound according to the sketch below:
In call, r1 'volume calls the "lookup method" of -cuboid- and returns the volume procedure, which is then called with the obj argument, binding that to the name this
Thus, this gets bound to the r1 argument to call
I need to make the function defmacro for my meta-circular interpreter that can read this syntax:
pseudoscheme> (defmacro (minus x y) (list ‘- y x))
MINUS
pseudoscheme> (expand-macro '(minus 3 2))
(- 3 2)
When I use this:
(defmacro my-defmacro ((name &rest args) &body body)
(let ((form (gensym))(env (gensym)))
(progn
`(setf (macro-function ',name)
(lambda (,form ,env))
(destructuring-bind ,args (rest, form) ,#body))
name
)
)
)
and then:
(my-defmacro (min a b)(list '- a b))
I get this error:
Error: The variable MIN is unbound.
I can't understand why.
-----EDITED-----
If I use this:
(defmacro my-defmacro ((name &rest args) &body body)
(let ((form (gensym))(env (gensym)))
`(progn (setf (macro-function ',name)
(lambda (,form ,env))
(destructuring-bind ,args (rest, form) ,#body))
',name)
)
)
and then:
(my-defmacro (min a b)(list '- a b))
I get this error:
Error: Odd number of args to SETF: ((MACRO-FUNCTION (QUOTE PLUS)) (LAMBDA (#:G786 #:G787)) (DESTRUCTURING-BIND (A B) (REST #:G786) (LIST # A B)))
Your my-defmacro works for you host CL system, but I get the feeling you want macro capabilities in your interpreter and this won't do it. (except if ythe interpreter environment is the global host implementations environment, but that would make a lot of challenges)
I don't know how you do compound procedures in your evaluator but when my evaluator gets a (lambda (x) (+ x x)) it is turned into (compound-procedure <env> (x) (+ x x)). My macros turn into almost the same except the first element is compound-syntax.
Every evaluated operator has a tag which tells it what it is (one of primitive-syntax, primitive-procedure, compound-syntax, compound-procedure) and I only need a general way of dealing with those 4.
The real difference between a compound procedure and compound syntax is that the arguments gets evaluated for a procedure and in a compound syntax the result gets evaluated.
So. Have you implemented so that ((lambda (x) (+ x x)) 5) works? Well, then you'll almost implemented macros as well. This is of course not true for a compiler, since this approach would expand the code every time it's run instead of expanding once when the closure gets created. (Optimizations is no way to go on the first version anyway)
For your 'edited code' you have a misplaced paren:
(defmacro my-defmacro ((name &rest args) &body body)
(let ((form (gensym))(env (gensym)))
`(progn (setf (macro-function ',name)
(lambda (,form ,env)) ;; <== HERE
(destructuring-bind ,args (rest, form) ,#body))
',name)
)
)
which leads to setf having three subforms. Rewrite it like this (while using standard Lisp formatting):
(defmacro my-defmacro ((name &rest args) &body body)
(let ((form (gensym))
(env (gensym)))
`(progn (setf (macro-function ',name)
(lambda (,form ,env)
(destructuring-bind ,args (rest, form)
,#body)))
',name)))