I try to combine Iteration technique and car/cdr recursion to search
in a database. Consider this peace of program for a datase wich look
like this:
name george
familyname bush
age 29
tlf 555-432343
=
name cathrine
familyname bush
age 18
tlf 555-55432
=
name george
familyname mc donnald
age 32
tlf 555-22222
tlf 555-33333
=
;; I put the database in a variable
(setf data-file (read-database "c:\database.txt"))
(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)))))
;; this converts the database into lists
(defun read-database (pathname)
(with-open-file (stream pathname :direction :input)
(loop
for address = (read-entry stream)
until (eq address stream)
collect address)))
(defun name (x)
(and (consp x) (eq (car x) 'name)))
(defun tlf (x)
(and (consp x) (eq (car x) 'tlf)))
(defun get-name ()
(cdar (remove-if-not #'name data-file)))
(defun get-tlf ()
(cdar (remove-if-not #'tlf data-file)))
(defun get-tlf-info (name)
(cond ((null name) nil)
((equal (cdar (remove-if-not #'get-name (read-database
data-file)))
name)
(cons (cdar (remove-if-not #'get-nr (read-database)))
(get-tlf-nr (cdr datafile))))))
I have already problem with:
(remove-if-not #'name '(name george))
which will return nil and I expect it to return GEORGE
and the main function (get-tlf-info 'george) that is supposed to give
me all the tlf.numbers to all the persons with the name george will
give me this error-message:
Error: Argument is not of type PATHNAME, STRING, or FILE-STREAM.
I also tried (get-tlf-info "c:\database.txt") it gives the same error
message.
ab talebi
············@yahoo.com (ab talebi) writes:
> I have already problem with:
> (remove-if-not #'name '(name george))
> which will return nil and I expect it to return GEORGE
I'm not sure if I understand your desire here.
REMOVE-IF-NOT takes a predicate as its first argument, not an item.
#'NAME would be a function whose name is NAME. If you want to remove
the symbol called NAME, you want (remove 'name '(name george)) which
will return (GEORGE) [not GEORGE]. No built-in removal function is
going to return the symbol GEORGE [i.e., as a symbol instead of a list
of symbols] since removal functions turn lists into other lists [of the
same or smaller length].
This whole thing where to find the value of an alist item, you remove
everything in the alist that is not the item, though, is very misguided.
I recommend instead using FIND or ASSOC to *find* the item and then
destructure the result of that.
> and the main function (get-tlf-info 'george) that is supposed to give
> me all the tlf.numbers to all the persons with the name george will
> give me this error-message:
>
> Error: Argument is not of type PATHNAME, STRING, or FILE-STREAM.
>
> I also tried (get-tlf-info "c:\database.txt") it gives the same error
> message.
Make sure to double your backslashes (\). Backslash is an escape character
in strings. It syntactically quotes the next character following.
"\\" is a one-letter string containing a backslash (\)
"\"" is a one-letter string containing a doublequote (")
"\:" (from your example) is a one-letter string containing a colon,
and is more commonly written ":" since colon requires no quoting.
So "C:\database.txt" will be seen by Lisp the same as "C:database.txt",
which may not be what you want.
In article <···············@shell01.TheWorld.com>,
Kent M Pitman <······@world.std.com> wrote:
>············@yahoo.com (ab talebi) writes:
>
>> I have already problem with:
>> (remove-if-not #'name '(name george))
>> which will return nil and I expect it to return GEORGE
>
>I'm not sure if I understand your desire here.
>
>REMOVE-IF-NOT takes a predicate as its first argument, not an item.
>#'NAME would be a function whose name is NAME.
I think you missed this in his post:
(defun name (x)
(and (consp x) (eq (car x) 'name)))
So NAME is a predicate that tells whether something is a cons whose car is
NAME. It would be more consistent with Lisp naming conventions if this
function were called NAMEP.
His problem is that REMOVE-IF-NOT doesn't pass the conses that form the
backbone of the list to the predicate, it passes the list elements. So he
should change his predicate to:
(defun namep (x)
(eq x 'name))
or switch to REMOVE, as you said.
--
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
It would have been simpler if he had just posted his homework problem.
sl
Barry Margolin wrote:
> In article <···············@shell01.TheWorld.com>,
> Kent M Pitman <······@world.std.com> wrote:
> >············@yahoo.com (ab talebi) writes:
> >
> >> I have already problem with:
> >> (remove-if-not #'name '(name george))
> >> which will return nil and I expect it to return GEORGE
> >
> >I'm not sure if I understand your desire here.
> >
> >REMOVE-IF-NOT takes a predicate as its first argument, not an item.
> >#'NAME would be a function whose name is NAME.
>
> I think you missed this in his post:
>
> (defun name (x)
> (and (consp x) (eq (car x) 'name)))
>
> So NAME is a predicate that tells whether something is a cons whose car is
> NAME. It would be more consistent with Lisp naming conventions if this
> function were called NAMEP.
>
> His problem is that REMOVE-IF-NOT doesn't pass the conses that form the
> backbone of the list to the predicate, it passes the list elements. So he
> should change his predicate to:
>
> (defun namep (x)
> (eq x 'name))
>
> or switch to REMOVE, as you said.
>
> --
> Barry Margolin, ······@genuity.net
> Genuity, Woburn, MA
> *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
> Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.