From: Mogens Neupart
Subject: Newbie: Please, help with undefined variable
Date: 
Message-ID: <42a5f9a8$0$653$edfadb0f@dread16.news.tele.dk>
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

From: Eric Lavigne
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <1118175115.411359.127590@g49g2000cwa.googlegroups.com>
> (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))
From: Eric Lavigne
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <1118175445.796599.196190@o13g2000cwo.googlegroups.com>
>>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))

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))
From: Mogens Neupart
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <42a60a9e$0$198$edfadb0f@dread11.news.tele.dk>
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:

>>>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))
> 
> 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))
From: Eric Lavigne
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <1118180012.184207.160200@z14g2000cwz.googlegroups.com>
>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))))))
From: Mogens Neupart
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <42aae97e$0$220$edfadb0f@dread11.news.tele.dk>
Hi Eric,
Thank you for your answer. It was the solution I was trying to obtain.

Best wishes,

Mogens



Eric Lavigne wrote:

>>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))))))
From: Frank Buss
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <1kpoqxqi7apnr$.1f02c3x6ysm9r.dlg@40tude.net>
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�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Mogens Neupart
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <42a610ab$0$304$edfadb0f@dread11.news.tele.dk>
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:
> 
>> 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
> 
From: Alan Crowe
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <86hdg8yg8e.fsf@cawtech.freeserve.co.uk>
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
From: Mogens Neupart
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <42aae758$0$220$edfadb0f@dread11.news.tele.dk>
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
From: Thomas A. Russ
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <ymi3brquoj2.fsf@sevak.isi.edu>
Mogens 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
From: Mogens Neupart
Subject: Re: Newbie: Please, help with undefined variable
Date: 
Message-ID: <42aae594$0$271$edfadb0f@dread11.news.tele.dk>
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 <·······@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.
> 
>