Home > Archive > Lisp > June 2005 > Newbie: Please, help with undefined variable
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Newbie: Please, help with undefined variable
|
|
| Mogens Neupart 2005-06-07, 8:58 pm |
| Hi all,
This may seem trivial to you "old-timers"; but I have a problem in line 4 of
the following code. I can see why I get an "Undefined variable"-error but
how do I make the inner str-variable visible to 'let'? It works fine in
lines 2 and 3.
1: (defun word (str)
2: (let ((str (string-left-trim '(#\Space) str)))
;Remove any leading spaces
3: (let ((spc (position #\Space str)))
;Find first trailing space - if any (Test for NIL)
4: (let ((str (str :end (- spc 1))))
;Isolate word before any trailing space(s)
5: (format t "~a : ~a" spc str)))))
Can anybody please tell me, what to do?
Is there a better way of isolating a word, retaining case?
Thanks in advance
Mogens
| |
| Eric Lavigne 2005-06-07, 8:58 pm |
| > (let ((str (str :end (- spc 1))))
The first str here is a variable.
The second str is a function (first argument is :end ... second
argument is (- spc 1))
Since there is no str function, you have a problem :)
>Can anybody please tell me, what to do?
>Is there a better way of isolating a word, retaining case?
Yes. In fact, the right way to do this is so easy that you probably
shouldn't even write this function, unless you prefer shorter function
names :)
(defun word (str)
(read-from-string str))
| |
| Eric Lavigne 2005-06-07, 8:58 pm |
| >>Can anybody please tell me, what to do?
[color=darkred]
>Yes. In fact, the right way to do this is so easy that you probably
>shouldn't even write this function, unless you prefer shorter function
>names :)
>(defun word (str)
> (read-from-string str))
I forgot. You don't just want to isolate the word. You also want to
print it. Try this:
(defun word (str)
(format t "~a : ~a" (read-from-string str) str))
| |
| Frank Buss 2005-06-07, 8:58 pm |
| Eric Lavigne wrote:
> Yes. In fact, the right way to do this is so easy that you probably
> shouldn't even write this function, unless you prefer shorter function
> names :)
>
> (defun word (str)
> (read-from-string str))
but you have to modify the readtable to preserve whitespace. Perhaps the OP
means this (fixing the "str" bug, better names for Lisp (in Lisp you
usually use verbose names) and standard formatting) :
(defun word (string)
(let ((string (string-left-trim '(#\Space) string)))
(let ((space (position #\Space string)))
(let ((string (subseq string 0 space)))
(format t "~a : ~a" space string)))))
If you want to extract all words, it could be written like this:
(defun word (string &key (start 0))
(let ((word-start (position-if-not #'(lambda (c) (char= c #\Space))
string
:start start)))
(unless word-start (setf word-start 0))
(let ((word-end (position #\Space string :start word-start)))
(values (subseq string word-start word-end) word-end))))
(defun words (string &key (start 0))
(multiple-value-bind (word end) (word string :start start)
(format t "~a~%" word)
(when end (words string :start end))))
CL-USER > (word "first word")
"first"
5
CL-USER > (words "Hello Lisp!")
Hello
Lisp!
NIL
--
Frank Buß, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
| |
| Mogens Neupart 2005-06-07, 8:58 pm |
| Hi Eric,
Thank you very much for your prompt response.
However, read-from-string gives me a problem with punctuation-marks; so
maybe I should use read-byte or read-char to catch escaped characters.
Eric Lavigne wrote:
>
>
>
> I forgot. You don't just want to isolate the word. You also want to
> print it. Try this:
>
> (defun word (str)
> (format t "~a : ~a" (read-from-string str) str))
| |
| Mogens Neupart 2005-06-07, 8:58 pm |
| Hi Frank,
Thank you for your input. It seems to be what I was looking for. I will have
a closer look at it and incorporate it into my small exercise.
Thanks again,
Mogens
Frank Buss wrote:
> Eric Lavigne wrote:
>
>
> but you have to modify the readtable to preserve whitespace. Perhaps the
> OP means this (fixing the "str" bug, better names for Lisp (in Lisp you
> usually use verbose names) and standard formatting) :
>
> (defun word (string)
> (let ((string (string-left-trim '(#\Space) string)))
> (let ((space (position #\Space string)))
> (let ((string (subseq string 0 space)))
> (format t "~a : ~a" space string)))))
>
> If you want to extract all words, it could be written like this:
>
> (defun word (string &key (start 0))
> (let ((word-start (position-if-not #'(lambda (c) (char= c #\Space))
> string
> :start start)))
> (unless word-start (setf word-start 0))
> (let ((word-end (position #\Space string :start word-start)))
> (values (subseq string word-start word-end) word-end))))
>
> (defun words (string &key (start 0))
> (multiple-value-bind (word end) (word string :start start)
> (format t "~a~%" word)
> (when end (words string :start end))))
>
> CL-USER > (word "first word")
> "first"
> 5
>
> CL-USER > (words "Hello Lisp!")
> Hello
> Lisp!
> NIL
>
| |
| Eric Lavigne 2005-06-07, 8:58 pm |
| >Thank you very much for your prompt response.
>However, read-from-string gives me a problem with punctuation-marks
How should punctuation marks be treated? The following function grabs a
substring starting with the first non-space and continuing until it
encounters another space (or end of string). Then it removes any
non-alphabetic characters (such as punctuation) and prints the result.
(defun word (string)
(let ((string (string-left-trim '(#\Space) string)))
(let ((space (position #\Space string)))
(let ((string (subseq string 0 space)))
(format t "~a : ~a"
space
(remove-if-not #'alpha-char-p
string))))))
| |
| Alan Crowe 2005-06-08, 4:00 pm |
| Mogens Neupart asked about trimming spaces to get at a word
in a string.
1: (defun word (str)
2: (let ((str (string-left-trim '(#\Space) str)))
;Remove any leading spaces
3: (let ((spc (position #\Space str)))
;Find first trailing space - if any (Test for NIL)
4: (let ((str (str :end (- spc 1))))
;Isolate word before any trailing space(s)
5: (format t "~a : ~a" spc str)))))
STRING-LEFT-TRIM doesn't work quite as nicely as usual here
because you compute the position relative to the trimmed
string. When you throw away the trimmed string the meaning
of the position value becomes opaque
Try
(defun character-predicate (target-char)
(lambda(test-char)
(char= target-char test-char)))
(defun first-word (string)
(let* ((initial-character (position-if-not (character-predicate #\Space)
string))
(terminating-space (position #\Space string
:start initial-character)))
(list terminating-space
(subseq string
initial-character
terminating-space))))
(defun word (string)
(format t "~{~A~^ : ~}" (first-word string)))
(first-word " foo bar") => (6 "foo")
i.e. first-word returns a list.
The REPL prints the list.
The REPL quotes strings when it prints them.
CL-USER(8): (word " foo bar")
6 : foo <= word printed this with format ~A so no quotes
NIL <= the REPL printed the NIL return value
CL-USER(9):
Play with character-predicate like this:
CL-USER(18): (funcall (character-predicate #\a) #\a)
T
CL-USER(19): (funcall (character-predicate #\a) #\b)
NIL
CL-USER(20): (mapcar (character-predicate #\b)
'(#\a #\b #\c))
(NIL T NIL)
CL-USER(21): (map 'list (character-predicate #\b)
"abc")
(NIL T NIL)
Alan Crowe
Edinburgh
Scotland
| |
| Thomas A. Russ 2005-06-10, 4:00 pm |
| Mogens Neupart <neupart@pc.dk> writes:
>
> Hi all,
>
> This may seem trivial to you "old-timers"; but I have a problem in line 4 of
> the following code. I can see why I get an "Undefined variable"-error but
> how do I make the inner str-variable visible to 'let'? It works fine in
> lines 2 and 3.
>
> 1: (defun word (str)
> 2: (let ((str (string-left-trim '(#\Space) str)))
> ;Remove any leading spaces
>
> 3: (let ((spc (position #\Space str)))
> ;Find first trailing space - if any (Test for NIL)
>
> 4: (let ((str (str :end (- spc 1))))
^
Are you missing a function here, like subseq?
> ;Isolate word before any trailing space(s)
>
> 5: (format t "~a : ~a" spc str)))))
>
> Can anybody please tell me, what to do?
Well, for starters, if you want to reuse the same variable name, I find
it much less confusing to use SETQ rather than rebinding it.
> Is there a better way of isolating a word, retaining case?
This seems to be a pretty standard method of doing what you want.
--
Thomas A. Russ, USC/Information Sciences Institute
| |
| Mogens Neupart 2005-06-11, 3:58 pm |
| Hi Thomas,
Thank you for your answer. I am pleased to hear that I have used some sort
of standard for for writing my exercise. In the thread posted by Frank Buss
I learned that I did indeed miss the subseq function. The same posting gave
me some ideas of how to extend my exercise.
Thanks again,
Mogens
Thomas A. Russ wrote:
> Mogens Neupart <neupart@pc.dk> writes:
>
> ^
> Are you missing a function here, like subseq?
>
>
> Well, for starters, if you want to reuse the same variable name, I find
> it much less confusing to use SETQ rather than rebinding it.
>
>
> This seems to be a pretty standard method of doing what you want.
>
>
| |
| Mogens Neupart 2005-06-11, 3:58 pm |
| Hi Alan,
Thank you for your example code. I will certainly try to experiment with it.
Frank Buss' posting contains a good solution to my problem; but as a
beginning Lisper I am keen to see different examples, so thanks again.
Mogens
Alan Crowe wrote:
> Mogens Neupart asked about trimming spaces to get at a word
> in a string.
>
> 1: (defun word (str)
> 2: (let ((str (string-left-trim '(#\Space) str)))
> ;Remove any leading spaces
>
> 3: (let ((spc (position #\Space str)))
> ;Find first trailing space - if any (Test for NIL)
>
> 4: (let ((str (str :end (- spc 1))))
> ;Isolate word before any trailing space(s)
>
> 5: (format t "~a : ~a" spc str)))))
>
> STRING-LEFT-TRIM doesn't work quite as nicely as usual here
> because you compute the position relative to the trimmed
> string. When you throw away the trimmed string the meaning
> of the position value becomes opaque
>
> Try
>
> (defun character-predicate (target-char)
> (lambda(test-char)
> (char= target-char test-char)))
>
> (defun first-word (string)
> (let* ((initial-character (position-if-not (character-predicate
> #\Space)
> string))
> (terminating-space (position #\Space string
> :start initial-character)))
> (list terminating-space
> (subseq string
> initial-character
> terminating-space))))
>
> (defun word (string)
> (format t "~{~A~^ : ~}" (first-word string)))
>
> (first-word " foo bar") => (6 "foo")
>
> i.e. first-word returns a list.
> The REPL prints the list.
> The REPL quotes strings when it prints them.
>
> CL-USER(8): (word " foo bar")
> 6 : foo <= word printed this with format ~A so no quotes
> NIL <= the REPL printed the NIL return value
> CL-USER(9):
>
> Play with character-predicate like this:
>
> CL-USER(18): (funcall (character-predicate #\a) #\a)
> T
> CL-USER(19): (funcall (character-predicate #\a) #\b)
> NIL
> CL-USER(20): (mapcar (character-predicate #\b)
> '(#\a #\b #\c))
> (NIL T NIL)
> CL-USER(21): (map 'list (character-predicate #\b)
> "abc")
> (NIL T NIL)
>
> Alan Crowe
> Edinburgh
> Scotland
| |
| Mogens Neupart 2005-06-11, 3:58 pm |
| Hi Eric,
Thank you for your answer. It was the solution I was trying to obtain.
Best wishes,
Mogens
Eric Lavigne wrote:
>
> How should punctuation marks be treated? The following function grabs a
> substring starting with the first non-space and continuing until it
> encounters another space (or end of string). Then it removes any
> non-alphabetic characters (such as punctuation) and prints the result.
>
> (defun word (string)
> (let ((string (string-left-trim '(#\Space) string)))
> (let ((space (position #\Space string)))
> (let ((string (subseq string 0 space)))
> (format t "~a : ~a"
> space
> (remove-if-not #'alpha-char-p
> string))))))
|
|
|
|
|