From: ab talebi
Subject: Help me; I don't get it
Date: 
Message-ID: <3bfa25ab.91503547@news.uio.no>
I try to fix the bugs in my programs but it still doesn't work, and I
just don't know why.
I have this file:

(setf data-file '(
((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
((NAME "george") (TLF"555-22222") (TLF "555-33333")))

and this function:

(defun extract (category value list)
  (cond ((null list) list)
  ((eq (cdr (assoc 'name list)) value)
  (list (assoc category list) (extract category value (cdr list))))
  (t (extract category value (cdr list)))))

Now: shouldn't (extract 'tlf 'george data-file) return all the tlf.
numbers of all my georges ? because it keeps returning NIL


ab talebi

From: H�kon Alstadheim
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m0oflxjvoz.fsf@alstadhome.cyberglobe.net>
············@yahoo.com (ab talebi) writes:

> I try to fix the bugs in my programs but it still doesn't work, and I
> just don't know why.
> I have this file:
> 
> (setf data-file '(
> ((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
> ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
> ((NAME "george") (TLF"555-22222") (TLF "555-33333")))
> 
> and this function:
> 
> (defun extract (category value list)
>   (cond ((null list) list)
>   ((eq (cdr (assoc 'name list)) value)
>   (list (assoc category list) (extract category value (cdr list))))
>   (t (extract category value (cdr list)))))
> 
> Now: shouldn't (extract 'tlf 'george data-file)  return all the tlf.
> numbers of all my georges ? because it keeps returning NIL

Small tip on editing: make sure you use an editor that helps you with
indenting.

Small tip on thinking: lisp is not text munging, you are working on
structures, try to see the structures you are working on in your mind.

Start solving your problem by drawing the list as boxes and arrows,
then build your code up from the inside out. Here are some starting
points:

What does (assoc 'name '((name "george"))) return when you type it at
the listener? What does (cdr '(name "gorge")) return ? Learn about
"dotted lists", and try (cdr '(name . "george")) or (cadr '(name
"george")). What does (eq "george" "george") return?

Look up the equal function in your reference of choice. A start might
be typing (describe 'equal) at the listener. Compare with (describe
'eq).

When you've got the comparison working, start on walking the list with
your box-and-arrow drawing in hand. Work your way through your
function from the outside in, by having the innermost levels just
print what you have in the variables.

-- 
H�kon Alstadheim, Montreal, Quebec, Canada  
From: lin8080
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3BFBEDE8.D87D3E3@freenet.de>
"H�kon Alstadheim" schrieb:

> Small tip on editing: make sure you use an editor that helps you with
> indenting.

> Small tip on thinking: lisp is not text munging, you are working on
> structures, try to see the structures you are working on in your mind.
[...]

This tips are very useful for me and I only wish to read more of that.
So thank you. The question, I wondered myself, is again and again: how
can you get so small code ? So this kind of postings are important to
newbie like me.

stefan
From: Christopher Stacy
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <uoflxegfq.fsf@spacy.Boston.MA.US>
>>>>> On Tue, 20 Nov 2001 09:47:59 GMT, ab talebi ("ab") writes:
 ab> I try to fix the bugs in my programs but it still 
 ab> doesn't work, and I just don't know why.

You can't program by just randomly changing things in your program 
and hoping it will eventually do what you want.  You first have to
really understand what your data is, how it is structured, and
then figure out a plan for how the program will work through
that structure and what decisions it needs to make at each step.
Then you write your program.   Debugging it means that you carefully
look at what you have written, breaking it down and getting an isolated
understanding of the parts that are working correctly.  Eventually you
will find the part that is not doing what you expect (that is, it's
not doing what the other parts expect it to be doing).

I don't know exactly what you're trying to do, but let's just take 
a look at some of the things that are going on and see which parts
make sense, and which parts don't.

 ab> I have this file:
 ab> (setf data-file '(
 ab> ((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
 ab> ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
 ab> ((NAME "george") (TLF"555-22222") (TLF "555-33333")))

 ab> and this function:

 ab> (defun extract (category value list)
 ab>   (cond ((null list) list)
 ab>   ((eq (cdr (assoc 'name list)) value)
 ab>   (list (assoc category list) (extract category value (cdr list))))
 ab>   (t (extract category value (cdr list)))))

 ab> Now: shouldn't (extract 'tlf 'george data-file) return all the tlf.
 ab> numbers of all my georges ? because it keeps returning NIL

It's hard to read your code unless it is indented properly,
so I pasted your code into Emacs and typed "c-m-Q" at it.
Here's what you have:

   (defvar *data*
     '(((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
       ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
       ((NAME "george") (TLF"555-22222") (TLF "555-33333"))))

I renamed it from DATA-FILE to *DATA* to be less misleading.
I see no "file" here.  Also, the asterisks around the variable
are the usual convention to indicate that it's a global variable.
And I have used DEFVAR to declare it as such.

Your data is an outermost list that contains three lists, 
each of which is a tuple of value names and values.

You can treat those inside lists could be considered to be an
association-list, so the ASSOC function can be used to search them:

   (assoc 'tlf '((NAME "cathrine")
		 (FAMILYNAME "bush") 
		 (AGE "18") 
		 (TLF "555-55432")))

 => (TLF "555-55432")


But your program calls ASSOC on the outer list, not on any of those
alists contained within it.  ASSOC thinks you're handing it an alist
whose keys are things like (NAME "someone").   For example:

   (assoc '(NAME "cathrine") *data* :test 'equal)
 => ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))

I have not been following this discussion, so I am not
positive what your program below is supposed to be doing.

   (defun extract (category value list)
     (cond ((null list) 
            list)
           ((eq (cdr (assoc 'name list)) value)
            (list (assoc category list)
                  (extract category value (cdr list))))
           (t
            (extract category value (cdr list)))))

I am guessing that your program is supposed to extract all the 
data in indicated category from all of the tuples.  
Maybe you wanted something like this:

   (defun extract (category name list)
     (when list
       (if (eq (cadr (assoc 'name (car list))) 
	       name)
	   (append (assoc category (car list))
		   (extract category name (cdr list)))
	 (extract category name (cdr list)))))

The most important change to your program is in that call to ASSOC.
You're using recursion to process pieces of LIST, by using CDR to
get each of the successive alists for ASSOC.   But as I explained
above, you are passing the entire list-of-lists (or a CDR'd piece
of that) to ASSOC.  You want ASSOC to look at one of the alists,
not at the remaining list of alists.   So you need to call ASSOC
on the CAR of LIST, not on the whole LIST.

Equally importat, I changed your (CDR (ASSOC ...)) into (CADR (ASSOC...)) 
because you composed your alists as lists, rather than as simple conses.  

The list           (FOO BAR) 
is not the same as (FOO . BAR) 

You can most easily understand this by comparing how 
you would draw a diagram of both.

I changed your COND into the more simple IF, since there were really
only two cases.  

You wrote  (COND ((NULL LIST) LIST))
specifying that you return LIST when you know LIST is NIL.
But the point is not about LIST, it's about NIL.
I might have changed that to be   (COND ((NULL LIST) NIL)).
I decided that (UNLESS (NULL LIST) ...do everything...)
was a better way to emphasize the point of termination
of your recursive algorithm.    This is a stylistic change
that does not affect your algorithm, but which might make
it easier to understand when you're looking at it.

I renamed the variable VALUE to be NAME, because it is always a name
that ASSOC must be looking for.  It can't look for any other category,
because you already hardcoded that.   If something is specific and
nailed down like that, don't mislead people with the appearance
that something more general-purpose is possible.

 ab> (EXTRACT 'TLF 'GEORGE DATA-FILE)

In your example, you pass in the name GEORGE, which is a symbol.  
But your data set has names that are strings, like "george".  
The string "george" is not the same as symbol GEORGE.

One easy solution would be to change your data so that the names 
are symbols, rather than strings.

Another solution would be to call your function like this:
 ab> (EXTRACT 'TLF "george" DATA-FILE)
but that still won't work because you are using EQ to do the
comparisons.  EQ asks if two objects are the same object,
rather like comparing two pointers.   This is not the same
as doing a string-compare.  If you want to use strings,
you will have to change from EQ to the function EQUAL,
which can be used to compare strings.

In my example, I changed the data so that names were symbols,
such as GEORGE.  I left the telephone numbers as strings. 
Since we are not trying to compare TLFs to each other or
anything, we don't need to modify that part of the program.

I also changed your call to LIST into a call to APPEND.
Otherwise, you are collecting a list for each part of the 
result, including an empty list.  If you do that, 
the answer will look like this:

   ((TLF "555-432343") ((TLF "555-22222") NIL))

APPEND makes a new list by combining all the lists that you 
give it, so your answer will look like this:

   (TLF "555-432343" TLF "555-22222")

That may or may not be what you were hoping for.

There's one last big problem with your program.
I can see in the data that one of the entries for GEORGE has
two telephone numbers (but no AGE or FAMILYNAME).
ASSOC only finds the first matching item in an alist:

   (assoc 'apple '((bannana . bread)
	           (carot . cake)
	           (apple . pan-dowdy)
	           (apple . sauce)))
 => (APPLE . PAN-DOWDY)

I think you need to start out by trying again to understand the list
structure of your data, by diagraming it out. Writing it down in Lisp
with better indentation will also help you see it better.

Hope this helps!
From: Christopher Stacy
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <uitc5efw7.fsf@spacy.Boston.MA.US>
>>>>> On Tue, 20 Nov 2001 09:47:59 GMT, ab talebi ("ab") writes:
 ab> I try to fix the bugs in my programs but it still 
 ab> doesn't work, and I just don't know why.

You can't program by just randomly changing things in your program 
and hoping it will eventually do what you want.  You first have to
really understand what your data is, how it is structured, and
then figure out a plan for how the program will work through
that structure and what decisions it needs to make at each step.
Then you write your program.   Debugging it means that you carefully
look at what you have written, breaking it down and getting an isolated
understanding of the parts that are working correctly.  Eventually you
will find the part that is not doing what you expect (that is, it's
not doing what the other parts expect it to be doing).

I don't know exactly what you're trying to do, but let's just take 
a look at some of the things that are going on and see which parts
make sense, and which parts don't.

 ab> I have this file:
 ab> (setf data-file '(
 ab> ((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
 ab> ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
 ab> ((NAME "george") (TLF"555-22222") (TLF "555-33333")))

 ab> and this function:

 ab> (defun extract (category value list)
 ab>   (cond ((null list) list)
 ab>   ((eq (cdr (assoc 'name list)) value)
 ab>   (list (assoc category list) (extract category value (cdr list))))
 ab>   (t (extract category value (cdr list)))))

 ab> Now: shouldn't (extract 'tlf 'george data-file) return all the tlf.
 ab> numbers of all my georges ? because it keeps returning NIL

It's hard to read your code unless it is indented properly,
so I pasted your code into Emacs and typed "c-m-Q" at it.
Here's what you have:

   (defvar *data*
     '(((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
       ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
       ((NAME "george") (TLF"555-22222") (TLF "555-33333"))))

I renamed it from DATA-FILE to *DATA* to be less misleading.
I see no "file" here.  Also, the asterisks around the variable
are the usual convention to indicate that it's a global variable.
And I have used DEFVAR to declare it as such.

Your data is an outermost list that contains three lists, 
each of which is a tuple of value names and values.

You can treat those inside lists could be considered to be an
association-list, so the ASSOC function can be used to search them:

   (assoc 'tlf '((NAME "cathrine")
		 (FAMILYNAME "bush") 
		 (AGE "18") 
		 (TLF "555-55432")))

 => (TLF "555-55432")


But your program calls ASSOC on the outer list, not on any of those
alists contained within it.  ASSOC thinks you're handing it an alist
whose keys are things like (NAME "someone").   For example:

   (assoc '(NAME "cathrine") *data* :test 'equal)
 => ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))

I have not been following this discussion, so I am not
positive what your program below is supposed to be doing.

   (defun extract (category value list)
     (cond ((null list) 
            list)
           ((eq (cdr (assoc 'name list)) value)
            (list (assoc category list)
                  (extract category value (cdr list))))
           (t
            (extract category value (cdr list)))))

I am guessing that your program is supposed to extract all the 
data in indicated category from all of the tuples.  
Maybe you wanted something like this:

   (defun extract (category name list)
     (unless (null list)
       (if (eq (cadr (assoc 'name (car list))) 
	       name)
	   (append (assoc category (car list))
		   (extract category name (cdr list)))
	 (extract category name (cdr list)))))

The most important change to your program is in that call to ASSOC.
You're using recursion to process pieces of LIST, by using CDR to
get each of the successive alists for ASSOC.   But as I explained
above, you are passing the entire list-of-lists (or a CDR'd piece
of that) to ASSOC.  You want ASSOC to look at one of the alists,
not at the remaining list of alists.   So you need to call ASSOC
on the CAR of LIST, not on the whole LIST.

Equally important, I changed your (CDR (ASSOC ...)) into (CADR (ASSOC...)) 
because you composed your alists from lists, rather than as simple conses.  

The list           (FOO BAR) 
is not the same as (FOO . BAR) 

You can most easily understand this by comparing how 
you would draw a diagram of both.

I changed your COND into the more simple IF, since there were really
only two cases.  

You wrote  (COND ((NULL LIST) LIST))
specifying that you return LIST when you know LIST is NIL.
But the point is not about LIST, it's about NIL.
I might have changed that to be   (COND ((NULL LIST) NIL)).
I decided that (UNLESS (NULL LIST) ...do everything...)
was a better way to emphasize the point of termination
of your recursive algorithm.    This is a stylistic change
that does not affect your algorithm, but which might make
it easier to understand when you're looking at it.

I renamed the variable VALUE to be NAME, because it is always a name
that ASSOC must be looking for.  It can't look for any other category,
because you already hardcoded that.   If something is specific and
nailed down like that, don't mislead people with the appearance
that something more general-purpose is possible.

 ab> (EXTRACT 'TLF 'GEORGE DATA-FILE)

In your example, you pass in the name GEORGE, which is a symbol.  
But your data set has names that are strings, like "george".  
The string "george" is not the same as symbol GEORGE.

One easy solution would be to change your data so that the names 
are symbols, rather than strings.

Another solution would be to call your function like this:
 ab> (EXTRACT 'TLF "george" DATA-FILE)
but that still won't work because you are using EQ to do the
comparisons.  EQ asks if two objects are the same object,
rather like comparing two pointers.   This is not the same
as doing a string-compare.  If you want to use strings,
you will have to change from EQ to the function EQUAL,
which can be used to compare strings.

In my example, I changed the data so that names were symbols,
such as GEORGE.  I left the telephone numbers as strings. 
Since we are not trying to compare TLFs to each other or
anything, we don't need to modify that part of the program.

I also changed your call to LIST into a call to APPEND.
Otherwise, you are collecting a list for each part of the 
result, including an empty list.  If you do that, 
the answer will look like this:

   ((TLF "555-432343") ((TLF "555-22222") NIL))

APPEND makes a new list by combining all the lists that you 
give it, so your answer will look like this:

   (TLF "555-432343" TLF "555-22222")

That may or may not be what you were hoping for.

There's one last big problem with your program.
I can see in the data that one of the entries for GEORGE has
two telephone numbers (but no AGE or FAMILYNAME).
ASSOC only finds the first matching item in an alist:

   (assoc 'apple '((bannana . bread)
	           (carot . cake)
	           (apple . pan-dowdy)
	           (apple . sauce)))
 => (APPLE . PAN-DOWDY)

I think you need to start out by trying again to understand the list
structure of your data, by diagraming it out. Writing it down in Lisp
with better indentation will also help you see it better.

Hope this helps!
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfa6872.6345156@news.uio.no>
On Tue, 20 Nov 2001 13:22:16 GMT, Christopher Stacy
<······@spacy.Boston.MA.US> wrote:

>I renamed it from DATA-FILE to *DATA* to be less misleading.
>I see no "file" here.  

>In your example, you pass in the name GEORGE, which is a symbol.  
>But your data set has names that are strings, like "george".  
>The string "george" is not the same as symbol GEORGE.
>
>One easy solution would be to change your data so that the names 
>are symbols, rather than strings.
>

thanks for you answer, it cleared up a lot of things. actually it is
not a good idea to have strings, it's much better with symbols. the
data-file looks like this (that is why I called it data-file, and not
*data*, but any way)
c:\data-file.txt
name	george
familyname	bush
age	29
tlf	555-432343
=
name	cathrine
familyname	bush
age	18
tlf	555-55432
=
name	george
tlf	555-22222
tlf	555-33333
=
to the left we have always only one word (category) and in front of
each category we have their value (can be more than one word). The
category is seperated of it's value by one or more spaces
the entries are seperated by = that comes after each entry.

In this function read-database the values are read as strings, which
is not what I want. How can I have the values as symbols and not
convert them to strings. Here are read-database and its aux-file
read-entry

(defun read-entry (stream)
  (loop
      for line = (read-line stream nil nil)
      when (null line)
      return stream
      until  (string-equal line "=")
      collect 
	(multiple-value-bind (key position) (let ((*read-eval* nil))
					      (read-from-string line))
	  (loop 
	      while (eq #\tab (char line position))
	      do (incf position))	; skip multiple tabs
	  (list key
		(subseq line position)))))

(defun read-database (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop
	for address = (read-entry stream)
	until (eq address stream)
	collect address)))
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m3g079ei6k.fsf@comail.ru>
Hello,

············@yahoo.com (ab talebi) writes:
> I try to fix the bugs in my programs but it still doesn't work, and I
> just don't know why.

LET and FLET are wonderful things.

> I have this file:
> 
> (setf data-file '(
> ((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
> ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
> ((NAME "george") (TLF"555-22222") (TLF "555-33333")))
> 
> and this function:
> 
> (defun extract (category value list)
>   (cond ((null list) list)
>   ((eq (cdr (assoc 'name list)) value)
>   (list (assoc category list) (extract category value (cdr list))))
>   (t (extract category value (cdr list)))))
> 
> Now: shouldn't (extract 'tlf 'george data-file) return all the tlf.
> numbers of all my georges ? because it keeps returning NIL

No, it should return NIL :-)

(setf *data-file* '(
((NAME . "george") (FAMILYNAME . "bush") (AGE . "29") (TLF . "555-432343"))
((NAME . "cathrine") (FAMILYNAME . "bush") (AGE . "18") (TLF . "555-55432"))
((NAME . "george") (TLF . "555-22222") (TLF . "555-33333")))
)

(defun find-category-values (category record)
  (loop for (current-category . value) in record
        when (eq current-category category) collect value))

(defun extract (category value list)
  (if (null list) 
      '()
      (let ((record (first list)))
        (if (equal (cdr (assoc 'name record)) value)
            (nconc (find-category-values category record)
                   (extract category value (rest list)))
            (extract category value (rest list))))))


---
* (extract 'tlf "george" *data-file*)
("555-432343" "555-22222" "555-33333")
---

Symbol GEORGE and string "GEORGE" are different objects; your data
file contains strings - you should search strings (which are compared
with EQUAL or EQUALP - not with EQ).

Regards,
Alexey Dejneka

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfa54a5.1275346@news.uio.no>
On 20 Nov 2001 15:32:51 +0300, Alexey Dejneka <········@comail.ru>
wrote:

>(setf *data-file* '(
>((NAME . "george") (FAMILYNAME . "bush") (AGE . "29") (TLF . "555-432343"))
>((NAME . "cathrine") (FAMILYNAME . "bush") (AGE . "18") (TLF . "555-55432"))
>((NAME . "george") (TLF . "555-22222") (TLF . "555-33333")))
>)
>
>(defun find-category-values (category record)
>  (loop for (current-category . value) in record
>        when (eq current-category category) collect value))
>
>(defun extract (category value list)
>  (if (null list) 
>      '()
>      (let ((record (first list)))
>        (if (equal (cdr (assoc 'name record)) value)
>            (nconc (find-category-values category record)
>                   (extract category value (rest list)))
>            (extract category value (rest list))))))
>

my original data-file is not a dotted list, and your extract will only
work if we have a dotted list.

>---
>* (extract 'tlf "george" *data-file*)
>("555-432343" "555-22222" "555-33333")
>---

that is wonderfull but it should return
(("555-432343") ("555-22222" "555-33333"))


ab talebi
From: Christophe Rhodes
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <sqy9l11tjw.fsf@cam.ac.uk>
············@yahoo.com (ab talebi) writes:

> [snipped almost "correct" solution]
>
> my original data-file is not a dotted list, and your extract will only
> work if we have a dotted list.
> 
> >---
> >* (extract 'tlf "george" *data-file*)
> >("555-432343" "555-22222" "555-33333")
> >---
> 
> that is wonderfull but it should return
> (("555-432343") ("555-22222" "555-33333"))

So perhaps you need to take the time to read and understand the code
that has been posted, so that you can make the modifications that you
think are necessary?

Why do you expect people here to do your homework for you?

Christophe
-- 
Jesus College, Cambridge, CB5 8BL                           +44 1223 510 299
http://www-jcsu.jesus.cam.ac.uk/~csr21/                  (defun pling-dollar 
(str schar arg) (first (last +))) (make-dispatch-macro-character #\! t)
(set-dispatch-macro-character #\! #\$ #'pling-dollar)
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m33d39s9ww.fsf@comail.ru>
············@yahoo.com (ab talebi) writes:
> my original data-file is not a dotted list, and your extract will only
> work if we have a dotted list.
Well, (compose #'cdr #'assoc) from your original solution works right
only with association lists, i.e. dotted. But, if your data structure
seem more natural to you, you can easily adapt it to your needs:

> >(defun find-category-values (category record)
> >  (loop for (current-category . value) in record
                                 ^
                          Remove this dot
> >        when (eq current-category category) collect value))
> >
> >(defun extract (category value list)
> >  (if (null list) 
> >      '()
> >      (let ((record (first list)))
> >        (if (equal (cdr (assoc 'name record)) value)
                       ^^^
                  Replace it with CADR
> >            (nconc (find-category-values category record)
                ^^^^^
           Replace it with CONS (*)
> >                   (extract category value (rest list)))
> >            (extract category value (rest list))))))
> >
> 

> >* (extract 'tlf "george" *data-file*)
> >("555-432343" "555-22222" "555-33333")
> >---
> 
> that is wonderfull but it should return
> (("555-432343") ("555-22222" "555-33333"))
Sorry, it was not evident for me: you wrote it should return
telephone numbers - and my version does. But see (*).

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfb7f57.6586042@news.uio.no>
On 20 Nov 2001 19:07:43 +0300, Alexey Dejneka <········@comail.ru>
wrote:

>············@yahoo.com (ab talebi) writes:
>> my original data-file is not a dotted list, and your extract will only
>> work if we have a dotted list.
>Well, (compose #'cdr #'assoc) from your original solution works right
>only with association lists, i.e. dotted. But, if your data structure
>seem more natural to you, you can easily adapt it to your needs:

yes, but the problem with strings remains. How can I read the content
of the database and handle the values as symbols not as a string?
the data-file looks like this
c:\data-file.txt
name	george
familyname	bush
age	29
tlf	555-432343
=
name	cathrine
familyname	bush
age	18
tlf	555-55432
=
name	george
tlf	555-22222
tlf	555-33333
=
to the left we have always only one word (category) and in front of
each category we have their value (can be more than one word). The
category is seperated of it's value by one or more spaces
the entries are seperated by = that comes after each entry.

These are the functions that read the database and put it in a list of
lists but the values are converted to strings, and I need to have them
as symbols so I can work on them

(defun read-entry (stream)
  (loop
      for line = (read-line stream nil nil)
      when (null line)
      return stream
      until  (string-equal line "=")
      collect 
	(multiple-value-bind (key position) (let ((*read-eval* nil))
					      (read-from-string line))
	  (loop 
	      while (eq #\tab (char line position))
	      do (incf position))	; skip multiple tabs
	  (list key
		(subseq line position)))))

(defun read-database (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop
	for address = (read-entry stream)
	until (eq address stream)
	collect address)))
From: Frogstar
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <fredrik.NOSPAMkavli-2111011340550001@1etg1.hit.uib.no>
In article <················@news.uio.no>, ············@yahoo.com wrote:

<snip>

Maybe I didn't get the problem stright, but something like this will turn
the data back to lists again.  I hate working on strings ;)

(defun string-to-list (str &optional (pos 0) (list nil))
  (multiple-value-bind (obj newpos)
       (read-from-string str nil :end-if-string :start pos)
    (if (eql obj :end-of-string)
       (nreverse list)
       (string-to-list str newpos (cons obj list)))))

Sorry if there's typos in here.

-- 
Remove Nospam for email.

...I made this!
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfbc643.7958525@news.uio.no>
On Wed, 21 Nov 2001 13:40:55 +0100, ···················@hit.uib.no
(Frogstar) wrote:

>In article <················@news.uio.no>, ············@yahoo.com wrote:
>
><snip>
>
>Maybe I didn't get the problem stright, but something like this will turn
>the data back to lists again.  I hate working on strings ;)
>
>(defun string-to-list (str &optional (pos 0) (list nil))
>  (multiple-value-bind (obj newpos)
>       (read-from-string str nil :end-if-string :start pos)
>    (if (eql obj :end-of-string)
>       (nreverse list)
>       (string-to-list str newpos (cons obj list)))))

what is the usage here? because
(string-to-list "  george") makes my lisp go vacouou
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m3vgg4ytrx.fsf@comail.ru>
············@yahoo.com (ab talebi) writes:

> >(defun string-to-list (str &optional (pos 0) (list nil))
> >  (multiple-value-bind (obj newpos)
> >       (read-from-string str nil :end-if-string :start pos)
                                         ^^
                          Should be :end-of-string
> >    (if (eql obj :end-of-string)
                         ^^
> >       (nreverse list)
> >       (string-to-list str newpos (cons obj list)))))
> 
> what is the usage here? because
> (string-to-list "  george") makes my lisp go vacouou

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: Fredrik A. Kavli
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <fredrik.andersen-2211010814520001@1etg1.hit.uib.no>
In article <················@news.uio.no>, ············@yahoo.com wrote:

> On Wed, 21 Nov 2001 13:40:55 +0100, ···················@hit.uib.no
> (Frogstar) wrote:
> 
> >In article <················@news.uio.no>, ············@yahoo.com wrote:
> >
> ><snip>
> >
> >Maybe I didn't get the problem stright, but something like this will turn
> >the data back to lists again.  I hate working on strings ;)
> >
> >(defun string-to-list (str &optional (pos 0) (list nil))
> >  (multiple-value-bind (obj newpos)
> >       (read-from-string str nil :end-if-string :start pos)
> >    (if (eql obj :end-of-string)
> >       (nreverse list)
> >       (string-to-list str newpos (cons obj list)))))
> 
> what is the usage here? because
> (string-to-list "  george") makes my lisp go vacouou

Sorry ab. the typo.  As already pointed out - it's supposed to be
<end-of-string> in line 3.  Can't allways make it right :)

-- 
frogstar

...I made this.
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfcbda7.71298971@news.uio.no>
On Thu, 22 Nov 2001 08:14:52 +0100,
················@spamit.student.uib.no (Fredrik A. Kavli) wrote:

>Sorry ab. the typo.  As already pointed out - it's supposed to be
><end-of-string> in line 3.  Can't allways make it right :)

yes, great, tnx
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m366841cvq.fsf@comail.ru>
Hello,

············@yahoo.com (ab talebi) writes:

> yes, but the problem with strings remains. 

Sorry, which problem?

> How can I read the content
> of the database and handle the values as symbols not as a string?

MAKE-SYMBOL, INTERN. And what is wrong with strings?

In <·················@news.uio.no> I see inconsistency: you put
strings in your data structure, but searched for a symbol. If you put
names as strings--search for strings; maybe using symbols for names is
better--I don't know your aim. But storing telephone numbers as
symbols seems too strange to me (think about city prefixes). 

Why have you decided to use symbols for names, lists [instead of
association lists/structures] for records (and to keep tlf numbers of
one person separately), list for a DB? (it is a question)

> the values are converted to strings, and I need to have them
> as symbols so I can work on them

What can not you do with strings? (EXTRACT, which I have posted you,
works fine with strings.)

Regards,
Alexey Dejneka

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfbc69e.8050265@news.uio.no>
On 21 Nov 2001 16:18:01 +0300, Alexey Dejneka <········@comail.ru>
wrote:


>What can not you do with strings? (EXTRACT, which I have posted you,
>works fine with strings.)

yes it does, but I can not take the 
(cdr "this is a string") but I can take (cdr '(this is a symbol-list))

take a look at these two functions that convert my database into list
of lists::

(defun read-entry (stream)
  (loop
      for line = (read-line stream nil nil)
      when (null line)
      return stream
      until  (string-equal line "=")
      collect 
	(multiple-value-bind (key position) (let ((*read-eval* nil))
					      (read-from-string line))
	  (loop 
	      while (eq #\tab (char line position))
	      do (incf position))	; skip multiple tabs
	  (list key
		(subseq line position)))))

(defun read-database (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop
	for address = (read-entry stream)
	until (eq address stream)
	collect address)))

Now take a look at the database

name	george
familyname	bush
age	29
tlf	555-432343
=
name	cathrine
familyname	bush
age	18
tlf	555-55432
=
name	george
tlf	555-22222
tlf	555-33333
=

to the left we have always only one word (category) and in front of
each category we have their value (can be more than one word). The
category is seperated of it's value by one or more spaces
the entries are seperated by = that comes after each entry.

my read-database function should leave the values alone and not
convert them to strings, meaning read-database should return:

((NAME george) (FAMILYNAME bush) (AGE 29) (TLF 555-432343))
((NAME cathrine) (FAMILYNAME bush) (AGE 18) (TLF 555-55432))
((NAME george) (TLF 555-22222) (TLF 555-33333)))

and not:
((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
((NAME "george") (TLF"555-22222") (TLF "555-33333")))


ab talebi
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m3r8qsysh3.fsf@comail.ru>
············@yahoo.com (ab talebi) writes:

> On 21 Nov 2001 16:18:01 +0300, Alexey Dejneka <········@comail.ru>
> wrote:
> 
> 
> >What can not you do with strings? (EXTRACT, which I have posted you,
> >works fine with strings.)
> 
> yes it does, but I can not take the 
> (cdr "this is a string") but I can take (cdr '(this is a
> symbol-list))

Aha. It seems to be very important in the example below. And it makes
memory economy. Maybe.

> 
> take a look at these two functions that convert my database into list
> of lists::
> 
> (defun read-entry (stream)
>   (loop
>       for line = (read-line stream nil nil)
>       when (null line)
>       return stream
>       until  (string-equal line "=")
>       collect 
vvv---
> 	(multiple-value-bind (key position) (let ((*read-eval* nil))
> 					      (read-from-string line))
> 	  (loop 
> 	      while (eq #\tab (char line position))
> 	      do (incf position))	; skip multiple tabs
> 	  (list key
> 		(subseq line position)))))
^^^---
> 
> (defun read-database (pathname)
>   (with-open-file (stream pathname :direction :input)
>     (loop
> 	for address = (read-entry stream)
> 	until (eq address stream)
> 	collect address)))

Have taken. Do you want to replace the parsing facility with
Frogstar's STRING-TO-LIST?

> Now take a look at the database
> 
> name	george
> familyname	bush
> age	29
> tlf	555-432343
> =
> name	cathrine
> familyname	bush
> age	18
> tlf	555-55432
> =
> name	george
> tlf	555-22222
> tlf	555-33333
> =

Also have taken.

> to the left we have always only one word (category) and in front of
                                                          ^^^^^^^^^^^
Behind?
> each category we have their value (can be more than one word). 
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
I see no such example, but I'll try to trust you.

<snip>

> my read-database function should leave the values alone and not
> convert them to strings, meaning read-database should return:
> 
> ((NAME george) (FAMILYNAME bush) (AGE 29) (TLF 555-432343))
> ((NAME cathrine) (FAMILYNAME bush) (AGE 18) (TLF 555-55432))
> ((NAME george) (TLF 555-22222) (TLF 555-33333)))
> 
> and not:
> ((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
> ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
> ((NAME "george") (TLF"555-22222") (TLF "555-33333")))

Aha, I see the following:

1. *NAMEs should be converted to symbols. 

  [Preserving case? Then 
   (eq 'george (cadr (assoc (car data-file)))) => NIL,
   and you should search for '|george|]

2. AGEs should be converted to numbers.

3. TLFs--to symbols(?)

Well, Frogstar have done all you've asked. Thank him.

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfcbe5b.71479236@news.uio.no>
On 21 Nov 2001 19:54:48 +0300, Alexey Dejneka <········@comail.ru>
wrote:

<....>

>> my read-database function should leave the values alone and not
>> convert them to strings, meaning read-database should return:
>> 
>> ((NAME george) (FAMILYNAME bush) (AGE 29) (TLF 555-432343))
>> ((NAME cathrine) (FAMILYNAME bush) (AGE 18) (TLF 555-55432))
>> ((NAME george) (TLF 555-22222) (TLF 555-33333)))
>> 
>> and not:
>> ((NAME "george") (FAMILYNAME "bush") (AGE "29") (TLF "555-432343"))
>> ((NAME "cathrine") (FAMILYNAME "bush") (AGE "18") (TLF "555-55432"))
>> ((NAME "george") (TLF"555-22222") (TLF "555-33333")))
>

>Well, Frogstar have done all you've asked. Thank him.

yes, Frogstars function works just fine, and I have also thanked him
:)) but it makes no sense to first convert the data from symbols to
string and then reconvert them to symbols. so the two initial
functions that put the database into lists should be changed to put
the database to list without changing the values to strings. I mean
the functions read-entry and read-database

(defun read-entry (stream)
  (loop
      for line = (read-line stream nil nil)
      when (null line)
      return stream
      until  (string-equal line "=")
      collect 
	(multiple-value-bind (key position) (let ((*read-eval* nil))
					      (read-from-string line))
	  (loop 
	      while (eq #\tab (char line position))
	      do (incf position))	; skip multiple tabs
	  (list key
		(subseq line position)))))

(defun read-database (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop
	for address = (read-entry stream)
	until (eq address stream)
	collect address)))

ab talebi
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m38zcysrnd.fsf@comail.ru>
············@yahoo.com (ab talebi) writes:

> it makes no sense to first convert the data from symbols to
> string and then reconvert them to symbols.

I also think so.

> so the two initial
> functions that put the database into lists should be changed to put
> the database to list without changing the values to strings. 

???!!! Where do you see a code converting values from SYMBOLs to
STRINGs?! 

Do you know where to insert a call for STRING-TO-LIST?

> I mean
> the functions read-entry and read-database
> 
> (defun read-entry (stream)
>   (loop
>       for line = (read-line stream nil nil)
>       when (null line)
>       return stream
>       until  (string-equal line "=")
>       collect 
> 	(multiple-value-bind (key position) (let ((*read-eval* nil))
> 					      (read-from-string line))
> 	  (loop 
> 	      while (eq #\tab (char line position))
> 	      do (incf position))	; skip multiple tabs
> 	  (list key
> 		(subseq line position)))))
> 
> (defun read-database (pathname)
>   (with-open-file (stream pathname :direction :input)
>     (loop
> 	for address = (read-entry stream)
> 	until (eq address stream)
> 	collect address)))
> 
> ab talebi

Regards,
Alexey Dejneka

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3bfe2611.3598132@news.uio.no>
On 22 Nov 2001 19:21:26 +0300, Alexey Dejneka <········@comail.ru>
wrote:


>Do you know where to insert a call for STRING-TO-LIST?

 my guess would be that we have to collect the result, meaning after
collect in 7th line but I'm not sure wich argument to call it with and
how to collect the result. Do I have to change read-database as well?

>> (defun read-entry (stream)
>>   (loop
>>       for line = (read-line stream nil nil)
>>       when (null line)
>>       return stream
>>       until  (string-equal line "=")
>>       collect 
>> 	(multiple-value-bind (key position) (let ((*read-eval* nil))
>> 					      (read-from-string line))
>> 	  (loop 
>> 	      while (eq #\tab (char line position))
>> 	      do (incf position))	; skip multiple tabs
>> 	  (list key
>> 		(subseq line position)))))
>> 
>> (defun read-database (pathname)
>>   (with-open-file (stream pathname :direction :input)
>>     (loop
>> 	for address = (read-entry stream)
>> 	until (eq address stream)
>> 	collect address)))
>> 

ab talebi
From: Alexey Dejneka
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <m3k7wgaeo4.fsf@comail.ru>
Hello,


············@yahoo.com (ab talebi) writes:

> On 22 Nov 2001 19:21:26 +0300, Alexey Dejneka <········@comail.ru>
> wrote:
> 
> 
> >Do you know where to insert a call for STRING-TO-LIST?
> 
>  my guess would be that we have to collect the result,
                                                         [into list]
Yes.

> meaning after collect in 7th line

Yes... But there already lies an expression (m-v-b ...)--what to do with it?

> but I'm not sure wich argument to call it with

You said you had tested it, so you should know how to call it.

> and how to collect the result.

Hmm...

> Do I have to change read-database as well?


> 
> >> (defun read-entry (stream)
> >>   (loop
> >>       for line = (read-line stream nil nil)
> >>       when (null line)
> >>       return stream
> >>       until  (string-equal line "=")
> >>       collect 
> >> 	(multiple-value-bind (key position) (let ((*read-eval* nil))
> >> 					      (read-from-string line))
> >> 	  (loop 
> >> 	      while (eq #\tab (char line position))
                     ^^
[It should be EQL (or CHAR=)--EQ is not guaranteed to work with characters]
> >> 	      do (incf position))	; skip multiple tabs
> >> 	  (list key
> >> 		(subseq line position)))))
> >> 
> >> (defun read-database (pathname)
> >>   (with-open-file (stream pathname :direction :input)
> >>     (loop
> >> 	for address = (read-entry stream)
> >> 	until (eq address stream)
> >> 	collect address)))
> >> 

Could you describe the precise meaning of each function
(READ-DATABASE, READ-ENTRY, STRING-TO-LIST)? And how do
they work? What is the meaning of each variable? (See HyperSpec
for descriptions of standard functions and special forms.)

Regards,
Alexey Dejneka

-- 
Greenspun's Tenth Rule of Programming as a reclame of Fortran
From: ab talebi
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <3c023f24.252824446@news.uio.no>
On 24 Nov 2001 09:03:39 +0300, Alexey Dejneka <········@comail.ru>
wrote:

>> meaning after collect in 7th line
>
>Yes... But there already lies an expression (m-v-b ...)--what to do with it?
>
 I'm not sure what you mean here by (m-v-b ...)

>Could you describe the precise meaning of each function
>(READ-DATABASE, READ-ENTRY, STRING-TO-LIST)? And how do
>they work? 

(defun read-entry (stream)
  (loop
      for line = (read-line stream nil nil)
      when (null line)
      return stream
      until  (string-equal line "=")
      collect 
	(multiple-value-bind (key position) (let ((*read-eval* nil))
					      (read-from-string line))
	  (loop 
	      while (eq #\tab (char line position))
	      do (incf position))	; skip multiple tabs
	  (list key
		(subseq line position)))))

(defun read-database (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop
	for address = (read-entry stream)
	until (eq address stream)
	collect address)))

actually I'm not sure as I got these functions from someone else, but
I try my best:
"read-entry" reads one entry (the sign =  is the deliminator for
entries) from our database file which looks like this:

name	george
familyname	bush
age	29
=
name catherine
familyname	toto
age	30
=
etc	etc
etc	etc
=

and puts it in this form:
((name "bush")(familyname "bush")(age "29"))

"read-database" uses "read-entry" to do the same thing for all the
entries in the database file and collect the result. Am I correct?

Now the problem is that we want read-database to return
((name bush)(familyname bush)(age 29))
not
((name "bush")(familyname "bush")(age "29"))

another thing is that read-database assumes that
name	george
are seperated by tab and they are really seperated by space.

both these issues should be solved within the collect part of the
function I think, but I'm not sure how:
<...>
collect 
	(multiple-value-bind (key position) (let ((*read-eval* nil))
					      (read-from-string line))
	  (loop 
	      while (eq #\tab (char line position))
	      do (incf position))	; skip multiple tabs
	  (list key
		(subseq line position))))
From: Coby Beck
Subject: Re: Help me; I don't get it
Date: 
Message-ID: <IgwM7.122562$Yb.31450449@typhoon.tampabay.rr.com>
"ab talebi" <············@yahoo.com> wrote in message
·······················@news.uio.no...
> On 24 Nov 2001 09:03:39 +0300, Alexey Dejneka <········@comail.ru>
> wrote:
> >Could you describe the precise meaning of each function
> >(READ-DATABASE, READ-ENTRY, STRING-TO-LIST)? And how do
> >they work?

[snip]

> actually I'm not sure as I got these functions from someone else, but

My friend, you may indeed get your assignment finished but you will learn
nothing if you continue your "ask c.l.l, copy, paste" approach.  People offer
you code, but if you can not understand the answer even when it is in front of
you, you had better try harder and stop asking for every little fix.
Modifying/debugging someone else's solution is already one step down in
learning value from doing it yourself from scratch; don't step even lower.

--
Coby
(remove #\space "coby . beck @ opentechgroup . com")