cartercc <carte...@gmail.com> writes: > On Feb 12, 8:18 am, p...@informatimago.com (Pascal J. Bourguignon) > wrote: >> But this is full of state mutation! How can you tell it's not buggy?
> I didn't say it was good code, and in fact wax pointed out a logic > error. All I said was that I would (and have) written this exercise > like this.
> At the risk of stirring up the natives, allow me this observation > concerning Lisp pedagogy. I've studied over a dozen languages so far, > learning about six well enough to use for real work. I'm a real big > fan of the Deitel series, owning the Deitel books in Java, Perl, C, C+ > +, and Visual Basic. Comparing those books to the Lisp books I'm using > (Wilensky, Graham, Seibel), Deitel beats you to death with exercises > that only vary a little -- but the end result /IF YOU DO ALL THE > EXERCISES/ is that you develop some facility with the material. The > Lisp books do not take this approach, apparently thinking that the > learner will make up his own exercises. Seibel is the worst offender > in this (not a criticism particularly in view of his practical > chapters) by not providing ANY end-of-chapter exercises. By way of > contrast, the Schwartz book 'Learning Perl' not only contains > exercises but also the answers. (I'm not saying that this book is > necessarily that good of a text - just making a comparison.)
> Personally, I would find it really helpful to have a series of go-slow > exercises, with the solutions, as an aid to learning. I'm trying to do > this on my own, but I really don't have the Lisp chops to do it, so > I'm pulling exercises from other sources that look like they relate to > a topic.
> The above is merely an observation, not a personal attack on anyone or > an insult to the Lisp community, so please, no flames.
Probably the lisp mind is self inquiring. When I self taught my first programming language, I had the reference manual. There were example programs, but no "exercises" properly. I wrote programs to exercise each statement I learned, one by one.
Lisp REPL is so natural and essential to the lispers, that it comes without saying that whenever you're presented with some lisp forms, you will be exercising it at the REPL, trying variations, playing with it.
cartercc <carte...@gmail.com> writes: > On Feb 12, 9:35 am, Marco Antoniotti <marc...@gmail.com> wrote: >> > ;;;------------------Marco Antoniotti-------------------- >> > ;;; doesn't prompt for input on the first instance >> > (defun gr-anton () >> > (loop with avg = 0.0 >> > initially (princ "Enter next grade, 'Q' to quit: ") >> > for grade = (read *standard-input* nil t) >> > while (numberp grade) >> > sum grade into total >> > count grade into count >> > do (setf avg (/ total count)) >> > do (format t "Grade: ~a, total: ~a, count: ~a, average: ~G~@ >> > Enter next grade, 'Q' to quit: " >> > grade total count avg) >> > finally (format t "~&Average is ~G~%" avg)))
>> Nope. It prints just fine. Check the INITIALLY clause.
>> Cheers >> -- >> Marco
> Just ran it again. I'm using clisp with slime. It still doesn't prompt > for the first input. Since it works for you and doesn't for me, could > it be something that is implementation dependent?
> I'm not trying to break anything, just trying to get everything to > run. I've spend the last two hours going through all the examples, and > have learned quite a bit - mostly the intricacies of loop.
It shouldn't prompt fir the first input. There's nothing in that code saying that it should.
First, for interactive querying, you should use *QUERY-IO*, not *standard-output* / *standard-input*. It could be tolerated to use *TERMINAL-IO*, but in cases such as those of slime, there's no directly accessible terminal. Use *QUERY-IO* to dialog with the user!
Then if you want to ensure that the user sees what you print, you should use FORCE-OUTPUT or FINISH-OUTPUT.
> On Feb 11, 11:34 am, cartercc <carte...@gmail.com> wrote:
> > The following script averages a series of grades from console input. I > > wrote it as if I would write a C program -- obviously not in idiomatic > > Lisp. How would one rewrite this in idiomatic Lisp?
> Thanks to all. Here is a clean copy of the scripts so far submitted, > warts and all. > ;;;-----------------Slobodan Blazeski--------------------------------- > (defun gr-blaze (&optional (s 0) (n 0)) > (princ "Enter next grade, 'Q' to quit: ") > (let ((g (read))) > (if (numberp g) > (progn > (format t "Grade: ~a, total: ~a, count: ~a, average: ~a~%" > g (+ g s) (1+ n) (/ (+ g s) (1+ n))) > (avg (+ g s) (1+ n))) > (format t "~%Average is ~g~%" (/ s n)))))
(gr-blaze) Enter next grade, 'Q' to quit: 22 Grade: 22, total: 22, count: 1, average: 22
Error: Undefined operator AVG in form (AVG (+ G S) (1+ N)). 1 (continue) Try invoking AVG again. 2 Return some values from the form (AVG (+ G S) (1+ N)). 3 Try invoking something other than AVG with the same arguments. 4 Set the symbol-function of AVG to another function. 5 Set the macro-function of AVG to another function. 6 (abort) Return to level 0. 7 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for other options
> On Feb 12, 3:24 pm, cartercc <carte...@gmail.com> wrote:
> > On Feb 11, 11:34 am, cartercc <carte...@gmail.com> wrote:
> > > The following script averages a series of grades from console input. I > > > wrote it as if I would write a C program -- obviously not in idiomatic > > > Lisp. How would one rewrite this in idiomatic Lisp?
> > Thanks to all. Here is a clean copy of the scripts so far submitted, > > warts and all. > > ;;;-----------------Slobodan Blazeski--------------------------------- > > (defun gr-blaze (&optional (s 0) (n 0)) > > (princ "Enter next grade, 'Q' to quit: ") > > (let ((g (read))) > > (if (numberp g) > > (progn > > (format t "Grade: ~a, total: ~a, count: ~a, average: ~a~%" > > g (+ g s) (1+ n) (/ (+ g s) (1+ n))) > > (avg (+ g s) (1+ n))) > > (format t "~%Average is ~g~%" (/ s n)))))
> (gr-blaze) > Enter next grade, 'Q' to quit: 22 > Grade: 22, total: 22, count: 1, average: 22
> Error: Undefined operator AVG in form (AVG (+ G S) (1+ N)). > 1 (continue) Try invoking AVG again. > 2 Return some values from the form (AVG (+ G S) (1+ N)). > 3 Try invoking something other than AVG with the same arguments. > 4 Set the symbol-function of AVG to another function. > 5 Set the macro-function of AVG to another function. > 6 (abort) Return to level 0. > 7 Return to top loop level 0.
> Type :b for backtrace, :c <option number> to proceed, or :? for other > options
> Do you know what have you done wrong?
> bobi
Yes, I didn't rename the recursive call. When I copied all the functions to one file, I had renamed it, but this must have come from my intermediate version. Anyway, the code works, and I think I like your version the best, mainly because it avoids the loop.
> > Personally, I would find it really helpful to have a series of go-slow > > exercises, with the solutions, as an aid to learning. I'm trying to do > > this on my own, but I really don't have the Lisp chops to do it, so > > I'm pulling exercises from other sources that look like they relate to > > a topic.
> On Feb 12, 9:35 am, Marco Antoniotti <marc...@gmail.com> wrote:
> > > ;;;------------------Marco Antoniotti-------------------- > > > ;;; doesn't prompt for input on the first instance > > > (defun gr-anton () > > > (loop with avg = 0.0 > > > initially (princ "Enter next grade, 'Q' to quit: ") > > > for grade = (read *standard-input* nil t) > > > while (numberp grade) > > > sum grade into total > > > count grade into count > > > do (setf avg (/ total count)) > > > do (format t "Grade: ~a, total: ~a, count: ~a, average: ~G~@ > > > Enter next grade, 'Q' to quit: " > > > grade total count avg) > > > finally (format t "~&Average is ~G~%" avg)))
> > Nope. It prints just fine. Check the INITIALLY clause.
> > Cheers > > -- > > Marco
> Just ran it again. I'm using clisp with slime. It still doesn't prompt > for the first input. Since it works for you and doesn't for me, could > it be something that is implementation dependent?
> I'm not trying to break anything, just trying to get everything to > run. I've spend the last two hours going through all the examples, and > have learned quite a bit - mostly the intricacies of loop.
Probably something to do with flushing of the buffers in CLisp. I use LWM most of the time.
> At the risk of stirring up the natives, allow me this observation > concerning Lisp pedagogy. I've studied over a dozen languages so far, > learning about six well enough to use for real work. I'm a real big > fan of the Deitel series, owning the Deitel books in Java, Perl, C, C+ > +, and Visual Basic. Comparing those books to the Lisp books I'm using > (Wilensky, Graham, Seibel), Deitel beats you to death with exercises > that only vary a little -- but the end result /IF YOU DO ALL THE > EXERCISES/ is that you develop some facility with the material. The > Lisp books do not take this approach, apparently thinking that the > learner will make up his own exercises. Seibel is the worst offender > in this (not a criticism particularly in view of his practical > chapters) by not providing ANY end-of-chapter exercises. By way of > contrast, the Schwartz book 'Learning Perl' not only contains > exercises but also the answers. (I'm not saying that this book is > necessarily that good of a text - just making a comparison.)
When Peter was sending out drafts for comments, he asked if I'd use it in a course, and I said the lack of exercises was a serious problem.
Graham's not so bad on that score, though I augmented and modified for my purposes.
On the other hand, most textbook exercises are like gym exercises. They work on one or two muscles but they're not about how it all works together. They often encourage using the wrong tool for a job *as an exercise* which would be fine if students were told that in real code not to invent the wheel.
cartercc wrote: > On Feb 11, 11:34 am, cartercc <carte...@gmail.com> wrote: >> The following script averages a series of grades from console input. I >> wrote it as if I would write a C program -- obviously not in idiomatic >> Lisp. How would one rewrite this in idiomatic Lisp?
> Thanks to all. Here is a clean copy of the scripts so far submitted, > warts and all.
Adding my own approach. In my idiom, I would not limit this to one function. I start with a vision of a simple loop that does the job, basically something that says
while next grade update and print stats print final average
Then I work as hard as possible to make that loop the first thing anyone sees, e.g.,
(defun gr-riesbeck () (let ((stats (make-instance 'stats))) (loop while (prin1 (add-grade (read-grade) stats))) (format t "~%Average is ~g~%" (stats-average stats))))
(defun read-grade () (princ "Enter next grade, 'Q' to quit: ") (read))
(defmethod add-grade (n (s stats)) (if (numberp n) (with-slots (grade total count average) s (setq grade n) (incf total n) (incf count) (setq average (/ total count)) s)))
(defmethod print-object ((s stats) stream) (with-slots (grade total count average) s (format stream "Grade: ~a, total: ~a, count: ~a, average: ~a~%" grade total count average)))
On 2009-02-12, cartercc <carte...@gmail.com> wrote:
> On Feb 11, 11:34 am, cartercc <carte...@gmail.com> wrote: >> The following script averages a series of grades from console input. I >> wrote it as if I would write a C program -- obviously not in idiomatic >> Lisp. How would one rewrite this in idiomatic Lisp?
> Thanks to all. Here is a clean copy of the scripts so far submitted, > warts and all.
On 2009-02-12, cartercc <carte...@gmail.com> wrote:
> On Feb 11, 11:34 am, cartercc <carte...@gmail.com> wrote: >> The following script averages a series of grades from console input. I >> wrote it as if I would write a C program -- obviously not in idiomatic >> Lisp. How would one rewrite this in idiomatic Lisp?
> Thanks to all. Here is a clean copy of the scripts so far submitted, > warts and all.
This is no good. You function has free references to symbols which have no definition in sight. Worse, you are assigning to them.
In Lisp you cannot use a symbolic form without defining it somewhere as a lexical variable or symbol macro, dynamic variable, constant, or global symbol macro.
Because assigning to an unbound symbol actually has some kind of effect in many Lisps (but not the exact same effect across all of them), the ANSI standard does not require the situation to be diagnosed as an unbound error.
The behavior is simply undefined!
> ;;;------------------Marco Antoniotti-------------------- > ;;; doesn't prompt for input on the first instance > (defun gr-anton () > (loop with avg = 0.0 > initially (princ "Enter next grade, 'Q' to quit: ") > for grade = (read *standard-input* nil t) > while (numberp grade) > sum grade into total > count grade into count > do (setf avg (/ total count)) > do (format t "Grade: ~a, total: ~a, count: ~a, average: ~G~@ > Enter next grade, 'Q' to quit: " > grade total count avg) > finally (format t "~&Average is ~G~%" avg)))
Nice. This one gets my vote, if there were to be a poll. :)
> This is no good. You function has free references to symbols which have no > definition in sight. Worse, you are assigning to them.
Which was one of the reasons I posted this thread. Due to my ignorance, I simply did not know how to do it.
> In Lisp you cannot use a symbolic form without defining it somewhere as a > lexical variable or symbol macro, dynamic variable, constant, or global symbol > macro.
Unlike C, or Perl, where you can declare a variable without assigning it a value. It's not enough to know that you can't do it, but WHY you can't do it.
> Because assigning to an unbound symbol actually has some kind of effect > in many Lisps (but not the exact same effect across all of them), the ANSI > standard does not require the situation to be diagnosed as an unbound error.
Okay, how would you explain that in language that someone who was not familiar with Lisp would understand? What is a symbol? Other languages don't seem to have them. Is it a variable? Why say that it is 'unbound' rather than saying that it has been declared but not yet assigned a value?
> The behavior is simply undefined!
Which means what? In Perl, my day-to-day language, undefined objects can play important, positive roles, that is, an object can exist but not be defined, you can test for that state, and use it as a boolean test for iteration or selection structures.
> > ;;;------------------Marco Antoniotti-------------------- > > ;;; doesn't prompt for input on the first instance > > (defun gr-anton () > > (loop with avg = 0.0 > > initially (princ "Enter next grade, 'Q' to quit: ") > > for grade = (read *standard-input* nil t) > > while (numberp grade) > > sum grade into total > > count grade into count > > do (setf avg (/ total count)) > > do (format t "Grade: ~a, total: ~a, count: ~a, average: ~G~@ > > Enter next grade, 'Q' to quit: " > > grade total count avg) > > finally (format t "~&Average is ~G~%" avg)))
> Nice. This one gets my vote, if there were to be a poll. :)
Why do you like it more than the others? (Not interested in right or wrong, but simply in your reasons for liking this one.)
cartercc wrote: > On Feb 12, 5:47 pm, Kaz Kylheku <kkylh...@gmail.com> wrote: >>> ;;;---------------------Charles Carter--------------------- >>> (defun gr-carter () >>> (progn >>> (setq total 0) >>> (setq count 0) >>> (setq avg 0) >> This is no good. You function has free references to symbols which have no >> definition in sight. Worse, you are assigning to them.
> Which was one of the reasons I posted this thread. Due to my > ignorance, I simply did not know how to do it.
>> In Lisp you cannot use a symbolic form without defining it somewhere as a >> lexical variable or symbol macro, dynamic variable, constant, or global symbol >> macro.
> Unlike C, or Perl, where you can declare a variable without assigning > it a value.
Did you just change the subject? Aside from that, not sure you want to say "unlike" when Lisp does the same as what you are unliking:
(defvar *wtf*)
> It's not enough to know that you can't do it, but WHY you > can't do it.
Because that is what the spec says? Too easy? If you were looking for a good reason, I would say that since the lamnguage has both dynamic and lexical scope that if a compiler comes across a variable it simply has never seen before then it is forced into guessing at whether someone forget defvar or let and it really hates guessing. so it guesses but yells (my lisp anyway).
>> Because assigning to an unbound symbol actually has some kind of effect >> in many Lisps (but not the exact same effect across all of them), the ANSI >> standard does not require the situation to be diagnosed as an unbound error.
> Okay, how would you explain that in language that someone who was not > familiar with Lisp would understand?
(1) become familiar with Lisp (2) read that again
> What is a symbol?
a data structure, in effect, with a name unique within a package. I think you are starting at the wrong end.
> Other languages > don't seem to have them. Is it a variable? Why say that it is > 'unbound' rather than saying that it has been declared but not yet > assigned a value?
because unbound is about ten words shorter?
>> The behavior is simply undefined!
> Which means what?
nose. demons. please note order.
> In Perl, my day-to-day language, undefined objects
> can play important, positive roles, that is, an object can exist but > not be defined, you can test for that state, and use it as a boolean > test for iteration or selection structures.
Sure. Ill-considered hacks of languages do all sorts of whacky things until they grow up if they do before they die.
On Fri, 13 Feb 2009 00:41:09 -0500, Kenneth Tilton wrote: > Sure. Ill-considered hacks of languages do all sorts of whacky things > until they grow up if they do before they die.
Always, it seems.
After your mention of Richard Gabriel the other day, I read a few papers from his web site, including "A Pattern of Language Evolution" (with Guy Steele, Jr.), which I thought was really interesting. There was a cool bit where some of the MacLisp users were complaining that one of the trade-offs intended to make it and Interlisp more similar was that (car nil) -> nil and (cdr nil) -> nil. The *reason* that they didn't like this is that up until then they'd been able to (cdr symbol) to get the property list for symbol (just because that's where it was stored in memory). They weren't concerned about the great boon that this would bring to the conciseness of their code (ref the thread on the finer points of car), but that this required that nil be treated differently from all of the other symbols. History is neat, huh?
On Feb 12, 6:23 pm, cartercc <carte...@gmail.com> wrote:
> Yes, I didn't rename the recursive call. When I copied all the > functions to one file, I had renamed it, but this must have come from > my intermediate version. Anyway, the code works, and I think I like > your version the best, mainly because it avoids the loop.
Thank you for your kind words, when you feel ready please consider joining the club of extended loop haters, functional style bigots and OO loathers. There is no entry fee but as per out first chairman recommendation there is tax on every use of: set setq setf psetf psetq incf decf push pop pushnew rplaca rplacd rotatef shiftf remf remprop remhash
cartercc <carte...@gmail.com> writes: >> The behavior is simply undefined!
> Which means what?
Which means that the standard doesn't say what will happen.
An implementation may say what will happen, but there could be implementation where this would still be undefined. That's where nasal demons enter the scene.
> In Perl, my day-to-day language, undefined objects > can play important, positive roles, that is, an object can exist but > not be defined, you can test for that state, and use it as a boolean > test for iteration or selection structures.
Perl is not defined. There's no perl standard. There's no alternative implementation.
>> This is no good. You function has free references to symbols which have no >> definition in sight. Worse, you are assigning to them.
> Which was one of the reasons I posted this thread. Due to my > ignorance, I simply did not know how to do it.
>> In Lisp you cannot use a symbolic form without defining it somewhere as a >> lexical variable or symbol macro, dynamic variable, constant, or global symbol >> macro.
> Unlike C, or Perl, where you can declare a variable without assigning > it a value.
I don't follow this. I didn't say that in Lisp you had to provide a value while defining a variable, but that you had to define a variable before using it.
You certainly can define a dynamic variable in Lisp without giving it a value.
> It's not enough to know that you can't do it, but WHY you > can't do it.
Why you can't use a variable without defining it is simply because that's how the language is.
There are languages in which you can just use a previously unknown name, and it magically becomes a variable right there, and even has some default value.
In the POSIX shell language you can evaluate $anything, and it works---unless checking for unset variables been turned on with ``set -u''. So the POSIX shell language is two languages in one: one in which variables must be defined before use, and a language in which they don't have to be.
>> Because assigning to an unbound symbol actually has some kind of effect >> in many Lisps (but not the exact same effect across all of them), the ANSI >> standard does not require the situation to be diagnosed as an unbound error.
> Okay, how would you explain that in language that someone who was not > familiar with Lisp would understand?
The prof teaching the course is supposed to understand the above language, and it's his job to teach that in a way that the students understand.
> What is a symbol? Other languages > don't seem to have them.
The term symbol is certainly used in other languages. C toolchains typically refer to object files has having ``symbols'', etc.
I wasn't using ``symbol'' as a Lisp data type here.
>? Is it a variable? Why say that it is > 'unbound' rather than saying that it has been declared but not yet > assigned a value?
Because unbound is roughly the opposite of defined or declared.
I.e. why would I say ``X'', if I really wanted to say ``not X''?
>> The behavior is simply undefined!
> Which means what?
Which means that the American national standard for the language does not impose any requirements about how a language implementation should respond to the construct.
If demons fly out of the programmer's nose, that is conforming behavior.
This is what ``undefined behavior'' commonly means in the definitions of many programming languages, not only in Lisp.
> In Perl, my day-to-day language, undefined objects
Well, your day-to-day language is a moving target that is defined by the behavior of its latest source code tarball.
> can play important, positive roles
``Undefined object'' is not the same thing as ``undefined behavior''.
A program defining a variable is a completely different ``defining'' from a language standard defining a requirement that a program or language implementation must mean.
> Why do you like it more than the others? (Not interested in right or > wrong, but simply in your reasons for liking this one.)
Because it neatly meets all of the requirements using features of LOOP, which are missed by some of the other implementations. So, in effect, it's all written in one programming language: the LOOP programming language.
cartercc <carte...@gmail.com> writes: > On Feb 12, 5:47ˇ pm, Kaz Kylheku <kkylh...@gmail.com> wrote:
[snip undeclared variable example]
> > In Lisp you cannot use a symbolic form without defining it somewhere as a > > lexical variable or symbol macro, dynamic variable, constant, or global symbol > > macro.
> Unlike C, or Perl, where you can declare a variable without assigning > it a value. It's not enough to know that you can't do it, but WHY you > can't do it.
Well, you can declare global (special = dynamic) variable without giving them a value. They are then UNBOUND. But since there is a difference in the behavior of special and lexical variables, it is good practice to declare any variables you wish to have be treated as special, since this is often a globally pervasive decision and affects the treatment of variables bound in LET blocks.
In fact, since the behavior is so different, Lisp coding style has adopted the very strong and nearly universal convention of denoting special variables by naming them so that they begin and end with asterisk ("*") characters. In fact, there are some lisps that will give a style warning for globally special variables that are not so named.
> > Because assigning to an unbound symbol actually has some kind of effect > > in many Lisps (but not the exact same effect across all of them), the ANSI > > standard does not require the situation to be diagnosed as an unbound error.
> Okay, how would you explain that in language that someone who was not > familiar with Lisp would understand? What is a symbol? Other languages > don't seem to have them.
That is correct. Most other languages DON'T have them. Symbols are one of the basic objects that exist in Common Lisp. They have many properties, but among them is that they can be bound to values, which makes them be variables.
> Is it a variable?
No. It is a first-class object in its own right. It may be used to name a variable, and when bound to values it acts like a variable. But it has additional functions as well. It can name a function and a class in addition to having a (lexical or dynamic) value.
> Why say that it is > 'unbound' rather than saying that it has been declared but not yet > assigned a value?
Because that is the lisp terminology. The association of a symbol with a value is called a "binding" of that symbol. So if there is no such binding, then the logical name for the state is "unbound". This is a fundamental term in lisp, so it's good to get used to it.
> > The behavior is simply undefined!
> Which means what?
It means that if you do that, you can't predict what a conforming implementation of Common Lisp will do. Now, all known implementations do something "reasonable", but exactly what that reasonable behavior is does vary, perhaps in subtle ways, between implementations.
The majority of lisps will treat references to undeclared variables as special (=dynamic) references to those variables. But that is done each time the variable is encountered, and doesn't affect the global state of declarations. In other lisps, notably CMUCL, setting the undeclared variable makes it be proclaimed to be globally special, on the assumption that the user reallly meant that, but forgot. That is different behavior because it affects the state of global definitions.
In all cases I'm aware of, the compiler will complain (issue a warning).
Those two compilers will treat the following code differently, and give you different answers:
(defun foo () (print a))
(setf a 10)
(let ((a 5)) (foo))
One implementation will print 5 and the other 10. And you can't complain because the behavior is not defined by the standard. That is precisely what "undefined behavior" means.
> In Perl, my day-to-day language, undefined objects > can play important, positive roles, that is, an object can exist but > not be defined, you can test for that state, and use it as a boolean > test for iteration or selection structures.
There is an important difference between a value being undefined and behavior being undefined. Even in Perl, you would probably not want to do something where the implementation says the effects are undefined (and thus not predictable).
Actually, Perl probably doesn't really have undefined objects, but rather it refers to pointers (variables) that don't point to any particular object. (Or else to a special value, "null", that isn't any object. I'm not really up on the details of Perl semantics).
-- Thomas A. Russ, USC/Information Sciences Institute