Page 1 of 1

need help

Posted: Tue Feb 10, 2009 12:59 pm
by joybee
Hello! Lisp Geeks,

This is my lisp practice project. I am trying to read an employee information from a text file, one employee info for one line and put into employee list and then to print out the result.

(defstruct employee first_name last_name mid_name birthday start_date title)
(defparameter employee_list (make-array 0 :adjustable t :fill-pointer 0))
(defun read_list (filename)
)
(defun print_list ())

Question:
How can I assigned the values from the text string to the employee structure and create employee array?

Thanks!

Joybee

Re: need help

Posted: Tue Feb 10, 2009 6:35 pm
by qbg
joybee wrote:Hello! Lisp Geeks,

This is my lisp practice project. I am trying to read an employee information from a text file, one employee info for one line and put into employee list and then to print out the result.

(defstruct employee first_name last_name mid_name birthday start_date title)
(defparameter employee_list (make-array 0 :adjustable t :fill-pointer 0))
(defun read_list (filename)
)
(defun print_list ())

Question:
How can I assigned the values from the text string to the employee structure and create employee array?

Thanks!

Joybee
First I'd like to point out that the standard naming convention in Lisp is to use hyphens instead of underscores, camel case, etc.

Now then, how are the lines of the text file formatted? Is this going to be CSV, or is it going to be delimited by spaces, or what?

Re: need help

Posted: Tue Feb 10, 2009 9:27 pm
by Paul Donnelly
joybee wrote:(defstruct employee first_name last_name mid_name birthday start_date title)
(defparameter employee_list (make-array 0 :adjustable t :fill-pointer 0))
(defun read_list (filename)
)
(defun print_list ())

Question:
How can I assigned the values from the text string to the employee structure and create employee array?
A few things.

An array seems like an odd choice for this program, especially for a prototype. I would think that lists will do fine for prototyping, and that any demanding application would be better served by a structure chosen for the type of lookups you will need to do.

You might also run into some trouble saving your list of employees in a variable. It could easily happen that you don't reset this variable between runs, and you end up thinking that read_list (or "read-list", as most of us would name it... well, I'd probably call it "employees-from" or something) is being properly updated, when in fact it contains garbage data from a previous run. This could be obvious to you, but I mention it because you may be used to working in a non-interactive environment where each run starts with a clean slate. Since you don't shut down your Lisp image between runs, any state you don't reset is retained — which is mostly a great thing, but can lead to silly errors. Personally, I would make read_list simply construct and return a list, and forget about side-effects. Since Lisp has a garbage collector, you can do this any time you want with no worries about memory leaks. Then you can test it by running (print_list (read_list)) at the REPL. Once you're sure read_list is working, you may want to save the data in a global variable for easy interactive testing purposes, but even so, you'll be better off if you pass that data as an argument rather than making print_list check out some hard-coded variable. (print_list employee_list), right?

As for doing the actual work, it depends, like qbg said, on your file format. Storing employee data as s-expressions is easiest. Then you can just READ from the file after setting *READ-EVAL* to nil to prevent code injection, if that's an issue. You'll get lists back, which are just about the easiest thing in the world to work with. If you've already got some files in another format, you'll just have to read lines as strings and parse them by hand.

I suspect print_list is going to be superfluous. The built-in PRINT function can print arrays and lists just fine. Lisp won't print anything interesting for your employee structure, but you can tell it what you want to see when you define the structure. Of course if there is a specific print format you'd like to see you'll need to write print_list.

Re: need help

Posted: Wed Feb 11, 2009 8:45 am
by joybee
Hello!

Thanks qbg and Paul for your help. And I really appreciate Paul's explanation, it helps me to learn some concepts. I just started to learn what a language Lisp is, it's difficult for me to apply the feature of the language in the coding while I felt coding is the best way to get some sense of programing. I made up this employee problem to learn the basic coding, so I guessed space could be the delimitier or maybe comma as the delimitier to deal with some empty fields.

I think I need to go back to do some reading and searching (Paul mentioned several new terms in his post) while you professionals help me to get start coding.

Re: need help

Posted: Thu Feb 12, 2009 8:51 am
by joybee
Is there a way to bind the text line I read from file directly to the structure or do I need to parse the line and assign the value individually? I just didn't get it. :-(

eg. one line read from the file is "Smith John H M 1018702738 1230432689 40000 Technician" in the order of last name, first name, middle init, sex, birthday, starting date, salary, title"
(defstruct employee lastname firstname middle....)
(with-open-file (in-stream ...)
(do ((line (read-line in-stream)
;;here how do I bind line to employee struct?
)

Thanks.

Re: need help

Posted: Thu Feb 12, 2009 3:04 pm
by Paul Donnelly
joybee wrote:Is there a way to bind the text line I read from file directly to the structure or do I need to parse the line and assign the value individually? I just didn't get it.
You need to parse it and assign values individually. BTW, once you split at commas you can use READ to turn a string of digits into a number.

Re: need help

Posted: Fri Feb 13, 2009 2:03 pm
by Harleqin
joybee wrote:Is there a way to bind the text line I read from file directly to the structure or do I need to parse the line and assign the value individually? I just didn't get it. :-(

eg. one line read from the file is "Smith John H M 1018702738 1230432689 40000 Technician" in the order of last name, first name, middle init, sex, birthday, starting date, salary, title"
(defstruct employee lastname firstname middle....)
(with-open-file (in-stream ...)
(do ((line (read-line in-stream)
;;here how do I bind line to employee struct?
)

Thanks.
You need to assign the values individually, but you can do so in more or less concise ways. The fastest way seems to be to modify the constructor in your defstruct declaration so that it takes slot values by order of arguments:

Code: Select all

(defstruct (employee (:constructor make-employee (last-name first-name middle-initial sex
                                                  birthday starting-date salary title)))
  last-name first-name middle-initial sex birthday starting-date salary title)
(By the way, since this constructor goes by order of arguments, it is sometimes called a "boa constructor". Yes, even in the ANSI standard.)
Now, given the arguments as a list (e.g. as returned from something like a get-employee-data function), you can call this constructor by using the "spreadable argument list designator" of apply:

Code: Select all

(apply #'make-employee (get-employee-data))
This now returns an employee struct with the specified data. For the get-employee-data function, you might want to look at the split function from the cl-ppcre package.

Disclaimer: I did not test any of the shown code.

Re: need help

Posted: Mon Mar 02, 2009 6:22 am
by Wodin
joybee wrote:eg. one line read from the file is "Smith John H M 1018702738 1230432689 40000 Technician" in the order of last name, first name, middle init, sex, birthday, starting date, salary, title"
By the way, one thing you might want to watch out for is, what happens when the last name is "van den Heever" or something like that.