I have been teaching computer science for a long time. The languages most often taught are C#, C++, Java, Python, etc. I add in examples from other languages such as Perl, Ruby, etc. each semester so that students can see the commonalities across languages. I have been trying my hand at Common Lisp and have to admit that for the first time in nearly 40 years i have hit the wall with a language.
Common Lisp has me stumped with getting a simple example program to compile and run. I need the code to run on ideone.com so that students can freely try it themselves and make changes to see what happens. I would greatly appreciate any help i can get with this...a full week of struggle is about all i can take.
Here is the code:
(defclass employee() ;;class definition header
((empid :accessor employee-empid;;member variable accessible and preset
:initform 230
:initarg :empid)
(name :accessor employee-name;;member variable accessible and preset
:intform 'bill
:intarg :name)
(pay :accessor employee-pay;;member variable accessible and preset
:initform 10
:initarg :pay)))
(defmethod infofun ( (p employee));;member method to allow two member vars to be changed
(print "The Worker: " : (employee-name p))
(setf (employee-pay p))
(setf (employee-empid p)))
(setq w1(make-instance 'employee :empid 100 :name 'worker1 :pay 47));;instance of class for w1
(setq w2(make-instance 'employee :empid 102 :name 'worker1 :pay 57));;instance of class for w2
(setq w3(make-instance 'employee :empid 103 :name 'worker1 :pay 67));;instance of class for w3
(describe w1);;get general info from List about the instance w1
(describe w2)
(describe w3)
(infofun w1);;run the member function, change the member vars
(infofun w2)
(infofun w3)
(setf (employee-pay w1) 147);;change a member var by code
(describe w1);;look at w1 again and note the values
(infofun w1);;change w1 again
(describe w1);;look at w1 one more time and check the new values
I hope somebody can help me with this.
thanks
Dr t
There are typos in your code: intarg instead of initarg, same with intform.
This line
(print "The Worker: " : (employee-name p))
has a colon in the midle.
Some setf like (setf (employee-pay p)) require two arguments, as you did later: (setf (employee-pay p) SOMETHING).
I can see that simply by writing in a real IDE.
I suggest you get Portacle, it's a portable and multiplatform Common Lisp dev environment that is straight forward to install: download and run. You'll be able to try your code with error messages. Portacle ships Emacs25, SBCL, Quicklisp, Slime and Git.
Good luck !
I hate to answer my own question but here goes...
I spent several hours working on this last night in spite of telling myself not to. If you are a programmer then you know what that is like. Finally the lights turned on and i realized that my class header had a 'type' but no place for the interpreter to bind an address. i just added a place. then i was able to make instances! I also simplified the class definition and took out all of the 'risky' code until it would run. then i went back to adding behaviors back in.
Here is what i came up with. I am working on a more better version.
(defclass employee-worker ()
(person-name empid));;extremely simple common lisp class definition
(defparameter *worker*(make-instance 'employee-worker));;constructor call for the first instance
(setf (slot-value *worker* 'person-name) "Joe Brown")
(setf (slot-value *worker* 'empid) "234")
(defparameter *worker2*(make-instance 'employee-worker));;constructor call for the second instance
(setf (slot-value *worker2* 'person-name) "John Brown")
(setf (slot-value *worker2* 'empid) "235")
(print "The first worker is: ")
(print (slot-value *worker* 'person-name))
(print "And his employee ID number is: ")
(print (slot-value *worker* 'empid))
(print "")
(print"The second worker is: ")
(print (slot-value *worker2* 'person-name))
(print "And his employee ID number is: ")
(print (slot-value *worker2* 'empid))
(setf (slot-value *worker* 'person-name) "Joe Green");;change the slot values for the first worker
(setf (slot-value *worker* 'empid) "432")
(print "The first worker is: ");;look at the first worker again to see the changes
(print (slot-value *worker* 'person-name))
(print "And his employee ID number is: ")
(print (slot-value *worker* 'empid))
Success time: 0 memory: 38056 signal:0
"The first worker is: "
"Joe Brown"
"And his employee ID number is: "
"234"
""
"The second worker is: "
"John Brown"
"And his employee ID number is: "
"235"
"The first worker is: "
"Joe Green"
"And his employee ID number is: "
"432"
I appreciate everyone helping.
Thanks
Dr t
Related
I have a struct with :name and :value that I'd like to use as arguments to a macro. But I'm not sure how to tell lisp that.
I can write out the call like
(sxql:yield (sxql:set= :name "a" :value 1))
"SET name = ?, value = ?"
("a" 1)
But I'd like to use an already existing structure
(defstruct my-struct name value)
(setq x (make-my-struct :name "a" :value 1))
; #S(MY-STRUCT :NAME "a" :VALUE 1)
using answers from Common LISP: convert (unknown) struct object to plist?
I've made
(defun struct-plist (x)
"make struct X into a property list. ugly kludge"
(let* ((slots (sb-mop:class-slots (class-of x)))
(names (mapcar 'sb-mop:slot-definition-name slots)))
(alexandria:flatten
(mapcar (lambda (n) (list (intern (string n) "KEYWORD")
(slot-value x n)))
names))))
(setq p (struct-plist x)) ; (:NAME "a" :VALUE 1)
My naive attempts are
(sxql:set= p) ; error in FORMAT: No more argument SET ~{~A = ~A~^, ~}
(funcall 'sxql:set= p) ; SXQL:SET= is a macro, not a function.
(macroexpand (sxql:set= p)) ; error in FORMAT ...
I imagine this is an easy/fundamental lisp programming question. But I'm not sure how to ask it (or search for answers). I'm also hoping there is an better struct<->plist story than what I've stumbled across so far.
EDIT: In case this is really an xy-problem. I've used flydata:defmodel to create the struct and I want to insert to a database using the same model.
This is definitely an xy problem: unfortunately I don't understand y (flydata?) well enough to answer the y part.
Here's why what you are trying to do can't work however. Consider this code in a file being compiled:
(defstruct mine name value)
...
(sxql:set= <anything derived from mine>)
Compiling this file must satisfy two constraints:
It does not fully create the structure type mine (see defstruct);
It must macroexpand sxql:set=.
What these constraints mean is that sxql:set= can't know about the structure at the time it is expanded. So any trick which relies on information about the structure must make that information available at compile time.
As I said, I don't understand the y part well enough to understand what you are trying to do, but a hacky approach to this is:
write a wrapper for defstruct which stashes information at compile time (strictly: at macro-expansion time);
write a wrapper for sxql:set= which uses that information to expand into something which makes sense.
Here is a mindless wrapper for defstruct. Note that this is mindless: it can only understand the most simple defstruct forms, and even then it may be wrong. It exists only as an example.
(eval-when (:compile-toplevel :load-toplevel :execute)
(defvar *structure-information* '()))
(defmacro define-mindless-structure (name &body slots)
(assert (and (symbolp name)
(every #'symbolp slots))
(name slots)
"I am too mindless")
(let ((found (or (assoc name *structure-information*)
(car (push (list name) *structure-information*)))))
(setf (cdr found) (mapcar (lambda (slot)
(list slot (intern (symbol-name slot)
(find-package "KEYWORD"))
(intern (concatenate 'string
(symbol-name name)
"-"
(symbol-name slot)))))
slots)))
`(defstruct ,name ,#slots))
So now
(define-mindless-structure mine
name value)
Will expand into (defstruct mine name value) and, at macroexpansion time will stash some information about this structure in *structure-information*.
Now I stop really understanding what you need to do because I don't know what sxql:set= is meant to do, but it might be something like this:
(defmacro mindless-set= ((s o))
(let ((info (assoc s *structure-information*))
(ov (make-symbol "O")))
(unless info
(error "no information for ~A" s))
`(let ((,ov ,o))
(sxql:set= ,#(loop for (slot initarg accessor) in (cdr info)
;; the compiler will whine about slot annoyingly
collect initarg
collect `(,accessor ,ov))))))
So with this macro, assuming a suitable define-mindless-structure for mine form has been seen by the time the macro is expanded, then
(mindless-set= (mine it))
Will expand into
(let ((#:o it))
(set= :name (mine-name #:o) :value (mine-value #:o)))
But, as I said, I am not sure what the expansion you actually want is.
Finally, before even thinking about using anything like the above, it would be worth looking around to see if there are portability libraries which provide compile/macroexpansion-time functionality like this: there very well may be such, as I don't keep up with things.
I'm curious if there is a way to end a backquoted symbol list with a period following a comma inserted value.
Here is the sample code:
(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
(if (member item things)
`(you pick up the ,item and yeet it out the window.)
`(only realize the truth... there is no ,item.)))
This will succeed (print (inspect-item 'book *things*)) and it produces the symbol list (YOU PICK UP THE BOOK AND YEET IT OUT THE WINDOW.). I assume in this case that the period is part of the symbol WINDOW. (as confirmed using the last function).
However, this will fail (print (inspect-item 'spoon *things*)) claiming that variable ITEM. has no value (Because it thinks the name is item.). Leaving a space between item and the period gives the error illegal end of dotted list which I assume is because it is assuming I'm using dotted list syntax.
Is there any way to get it to produce the symbol I want at the end (BOOK.)?
Possible requirements for a solution
You need to create a new symbol based on an old one:
the same name, with a . appended
probably in the same package
Period as a symbol
Note that you can write a symbol with the period as a name using an escaped symbol: |.| or \..
CL-USER 17 > (let ((item 'foobar))
`(only realize the truth... there is no ,item \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.)
princ prints without escape characters:
CL-USER 18 > (princ '(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR .) ; <- printed output
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.) ; <- REPL value
Solution
CL-USER 19 > (defun add-suffix (symbol suffix)
(intern (concatenate 'string
(symbol-name symbol)
(symbol-name suffix))
(symbol-package symbol)))
ADD-SUFFIX
CL-USER 20 > (let ((item 'tree))
`(we went to the ,(add-suffix item '|.|)))
(WE WENT TO THE TREE.)
It can also be useful to use the flexibility of format instead of using concatenate.
CL-USER 22 > (defun add-suffix (symbol suffix)
(intern (format nil "~a~a" symbol suffix)
(symbol-package symbol)))
ADD-SUFFIX
I think that the real problem lies in the attempt to produce text just as the printed representation of a list of symbols. Those are completely different things. The only reason to do it like this could be as some kind of exercise. There are a number of introductory texts that do that kind of thing.
Instead, I'd advise to actually produce text, i. e. strings. You might use the format function that is quite flexible for inserting variable things:
(defparameter *things* '("book" "pencil" "shoe"))
(defun inspect-item (item things)
(if (member item things :test #'string-equal)
(format nil
"You pick up the ~a and yeet it out the window."
item)
(format nil
"Only realize the truth… there is no ~a."
item)))
I partly agree with Svante that turning lists of symbols into text is often the wrong thing. On the other hand things like parsers &c often want to think in terms of symbols rather than strings as symbols have nice properties like (eq a b) working the way you would hope.
That being said, here's an alternative approach: create a list of words and then have a function which turns them into a string representing a sentence, adding appropriate punctuation and capitalization.
(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
(sentencify (if (member item things)
`(you pick up the ,item and yeet it out the window)
`(only realize the truth... there is no ,item))))
(defun sentencify (slist &key (question nil))
(format nil "~{~A~^ ~}~A"
(loop for first = t then nil
for w in slist
for ws = (typecase w
(symbol (symbol-name w))
(string w)
(t w))
collect (typecase ws
(string (if first
(string-capitalize ws)
(string-downcase ws)))
(t ws)))
(if question "?" ".")))
And now:
> (inspect-item 'book *things*)
"You pick up the book and yeet it out the window."
> (inspect-item 'bok *things*)
"Only realize the truth... there is no bok."
> (inspect-item '(x . y) *things*)
"Only realize the truth... there is no (x . y).
I am working through the MP3 database example in Peter Seibel's Practical Common Lisp. Seibel demonstrates how macros can be used to shorten the code for the where function; so now, I am trying to use a macro to shorten the code for the update function. (The original version of the update function is included for reference.) When I run my code, the following error originates from the second-to-last line --
*** - CAR: TERMS is not a list
What am I doing wrong? Here is my code.
(defvar *db* nil)
(defun add-record (cd)
(push cd *db*))
(defun dump-db ()
(dolist (cd *db*)
(format t "~{~a:~10t~a~%~}~%" cd)))
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
(defun prompt-for-cd ()
(make-cd
(prompt-read "Title")
(prompt-read "Artist")
(or (parse-integer (prompt-read "Rating") :junk-allowed t) 0)
(y-or-n-p "Ripped [y/n]: ")))
(defun add-cds ()
(loop (add-record (prompt-for-cd) )
(if (not (y-or-n-p "Another? [y/n]: ")) (return) )))
(defun save-db (filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
(defun load-db (filename)
(with-open-file (in filename)
(with-standard-io-syntax
(setf *db* (read in) ))))
(defun select (selector-fn)
(remove-if-not selector-fn *db*))
(defun make-comparison-expr (field value)
`(equal (getf cd ,field) ,value))
(defun make-comparison-list (func fields)
(loop while fields
collecting (funcall func (pop fields) (pop fields))))
(defmacro where (&rest clauses)
`#'(lambda (cd) (and ,#(make-comparison-list 'make-comparison-expr clauses))))
(defun make-update-expr (field value)
`(setf (getf row ,field) ,value))
(defmacro make-update-list (fields)
(make-comparison-list 'make-update-expr fields))
(defun update (selector-fn &rest terms)
(print (type-of terms))
(setf *db*
(mapcar
#'(lambda (row)
(when (funcall selector-fn row)
(make-update-list terms))
row)
*db*)))
;(defun update (selector-fn &key title artist rating (ripped nil ripped-p))
; (setf *db*
; (mapcar
; #'(lambda (row)
; (when (funcall selector-fn row)
; (if title (setf (getf row :title) title) )
; (if artist (setf (getf row :artist) artist) )
; (if rating (setf (getf row :rating) rating) )
; (if ripped-p (setf (getf row :ripped) ripped) ))
; row)
; *db*)))
(defun delete-rows (selector-fn)
(setf *db* (remove-if selector-fn *db*)))
;(loop (print (eval (read))))
(add-record (make-cd "Be" "Common" 9 nil))
(add-record (make-cd "Like Water for Chocolate" "Common" 9 nil))
(add-record (make-cd "Be" "Beatles" 9 nil))
(dump-db)
(update (where :artist "Common" :title "Be") :rating 8)
(dump-db)
-----Edit-----
I figured it out. The solution was to make update a macro and to make make-update-list a function. This way, make-update-list could evaluate fields at run-time and update can still abstract away some tedious if statements. Here is the updated update and make-update-list below:
(defun make-update-list (fields)
(make-comparison-list 'make-update-expr fields))
(defmacro update (selector-fn &rest terms)
`(setf *db*
(mapcar
#'(lambda (row)
(when (funcall ,selector-fn row)
,#(make-update-list terms))
row)
*db*)))
Macroexpansion of that make-update-list is done in a separate phase (called "macroexpansion phase") - which occurs around the time a piece of code is compiled or loaded; in this case we're talking about compilation / loading of update. The macro gets expanded with fields bound to the symbol terms, which (the symbol itself) is used as a value in make-comparison-list; I suppose that was not what you expected.
Note, if you go and compile the file line-by-line (C-c C-c in Emacs + SLIME), it'll tell you right during compilation of update that the macro expansion fails because "the value TERMS is not of type LIST".
Generally, think of macros as functions that take in their arguments unevaluated - i.e. a form (make-update-list foo) will get expanded with the macro parameter's fields value bound to foo. What you're trying to achieve here - code generation based on run-time values - is a bit more difficult to do.
You are trying to take the car of a symbol!
> (car 'terms)
*** - CAR: TERMS is not a list
Think of macros as a function that, when used, replaces the code with the result of the macro function everywhere it's used. At this time variables are just symbols and have no meaning besides that.
When you do (make-update-list terms) it will call the macro function with the argument fields being the symbol you passed, which is terms. Since it's a symbol it cannot be iterated like you are trying. You may iterate it at runtime when it surely is a list, but as a macro it isn't a list until you are passing it a list like (make-update-list (title artist rating ripped)).
If it is dynamic in runtime then your macro needs to expand to code that does most of its magic at runtime. Thus a macro is just a source rewriting service and should not have anything to do with what variable might be at runtime since then it has already done its thing.
Hi I am doing a condition which I just want to call a method if the condition is true, the problem is I cannot find the syntax how to create a method in C-Lisp I am new with this language here's the code.
/* I want to create a method here which i can all anytime in my condition but I am having problem with a syntax
(void method()
(print "Invalid")
)
*/
(print "Enter number")
(setq number(read())
(cond((< 1 number) (print "Okay"))
((> 1 number) /*I want to call a method here (the invalid one)*/ )
)
To create a function in common lisp you can use the defun operator:
(defun signal-error (msg)
(error msg))
Now you can call it like so:
(signal-error "This message will be signalled as the error message")
Then you can insert it in your code like this:
(print "Enter number")
(setq number (read)) ;; <- note that you made a syntax error here.
(cond ((< 1 number) (print "Okay"))
((> 1 number) (signal-error "Number is smaller than 1."))))
In your question you are asking about a method. Methods operate on classes. For example imagine you have two classes human and dog:
(defclass human () ())
(defclass dog () ())
To create a method specific for each class you use defmethod:
(defmethod greet ((thing human))
(print "Hi human!"))
(defmethod greet ((thing dog))
(print "Wolf-wolf dog!"))
Let's create two instances for each class:
(defparameter Anna (make-instance 'human))
(defparameter Rex (make-instance 'dog))
Now we can greet each living being with the same method:
(greet Anna) ;; => "Hi human"
(greet Rex) ;; => "Wolf-wolf dog!"
The process of common lisp knowing which method to execute is called "Dynamic dispatch". Basically it matches the given argument's classes to the defmethod definitions.
But I have no idea why you need methods in your code example.
Here is how I would write the code if I was you:
;; Let's wrap the code in a function so we can call it
;; as much as we want
(defun get-number-from-user ()
(print "Enter number: ")
;; wrapping the number in a lexical scope is a good
;; programming style. The number variable is not
;; needed outside the function.
(let ((number (read)))
;; Here we check if the number satisfies our condition and
;; call this function again if not.
(cond ((< number 1) (print "Number is less than 1")
(get-number-from-user))
((> number 1) (print "Ok.")))))
I would suggest you read "The Land of Lisp". It is great book for beginners.
To put it another, way, "Okay, so code is data..."
That thread addresses how to read from a source file, but I'm wondering how to get the s-expression of an already-loaded function into a data structure that I can read and manipulate.
In other words, if I say,
(defn example [a b] (+ a b))
can't I get that list at runtime? Isn't this the whole point of "code as data"?
This is really a general Lisp question, but I'm looking for an answer in Clojure.
You can use the clojure.repl/source macro to get the source of a symbol:
user> (source max)
(defn max
"Returns the greatest of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'max)}
([x] x)
([x y] (. clojure.lang.Numbers (max x y)))
([x y & more]
(reduce1 max (max x y) more)))
nil
But this is only part of the answer. AFAICT source looks up the source filename and line number that define the given symbol, and then prints the source code from the file. Therefore, source will not work on symbols that you do not have the source for, i.e. AOT-compiled clojure code.
Coming back to your original question, you can think of source as reading the meta data associated with the given symbol and simply printing that. I.e. it's cheating. It's not in any way returning "code as data" to you, where with code I mean a compiled clojure function.
In my mind "code as data" refers to the feature of lisps where source code is effectively a lisp data structure, and therefore it can be read by the lisp reader. That is, I can create a data structure that is valid lisp code, and eval that.
For example:
user=> (eval '(+ 1 1))
2
Here '(+ 1 1) is a literal list which gets read by the clojure reader and then evaluated as clojure code.
Update: Yehonathan Sharvit was asking in one of the comments if it's possible to modify the code for a function. The following snippet reads in the source for a function, modifies the resulting data structure, and finally evaluates the data structure resulting in a new function, my-nth, being defined:
(eval
(let [src (read-string (str (source-fn 'clojure.core/nth) "\n"))]
`(~(first src) my-nth ~#(nnext src))))
The syntax-quote line replaces nth with my-nth in the defn form.
You can get the source in recent versions of clojure with the source function.
user=> (source nth)
(defn nth
"Returns the value at the index. get returns nil if index out of
bounds, nth throws an exception unless not-found is supplied. nth
also works for strings, Java arrays, regex Matchers and Lists, and,
in O(n) time, for sequences."
{:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~#nf)))
:inline-arities #{2 3}
:added "1.0"}
([coll index] (. clojure.lang.RT (nth coll index)))
([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))
nil
to get the string as a value you can wrap this in with-out-str:
user=> (with-out-str (source nth))
"(defn nth\n \"Returns the value at the index. get returns nil if index out of\n bounds, nth throws an exception unless not-found is supplied. nth\n also works for strings, Java arrays, regex Matchers and Lists, and,\n in O(n) time, for sequences.\"\n {:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~#nf)))\n :inline-arities #{2 3}\n :added \"1.0\"}\n ([coll index] (. clojure.lang.RT (nth coll index)))\n ([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))\n"
user=>
That was my message; nice to meet you ;-) BTW, the references given in that thread for answers were excellent reading; so if you're interested, you might want to take the time to read them. Back to your question though source seems to work for code that was loaded through a file, but it doesn't work in all cases. I think, specifically, it doesn't work for functions defined in the repl.
user=> (def foo (fn [] (+ 2 2)))
#'user/foo
user=> (source foo)
Source not found
nil
user=> (defn foo2 [] (+ 2 2))
#'user/foo2
user=> (source foo2)
Source not found
nil
Digging a little bit...
user=> (source source)
(defmacro source
"Prints the source code for the given symbol, if it can find it.
This requires that the symbol resolve to a Var defined in a
namespace for which the .clj is in the classpath.
Example: (source filter)"
[n]
`(println (or (source-fn '~n) (str "Source not found"))))
nil
user=> (source clojure.repl/source-fn)
(defn source-fn
"Returns a string of the source code for the given symbol, if it can
find it. This requires that the symbol resolve to a Var defined in
a namespace for which the .clj is in the classpath. Returns nil if
it can't find the source. For most REPL usage, 'source' is more
convenient.
Example: (source-fn 'filter)"
[x]
(when-let [v (resolve x)]
(when-let [filepath (:file (meta v))]
(when-let [strm (.getResourceAsStream (RT/baseLoader) filepath)]
(with-open [rdr (LineNumberReader. (InputStreamReader. strm))]
(dotimes [_ (dec (:line (meta v)))] (.readLine rdr))
(let [text (StringBuilder.)
pbr (proxy [PushbackReader] [rdr]
(read [] (let [i (proxy-super read)]
(.append text (char i))
i)))]
(read (PushbackReader. pbr))
(str text)))))))
nil
So yeah, it looks like it tries to load the source file off the classpath to try to spit it out for you. One thing I've learned when working with Clojure is that 9 times out of 10 it is useful to look at the source.