Re: Newbie lisp problem: string to list of strings separated by space



Alan Crowe wrote:
Yossarian <yossarian@xxxxxxxxxxx> writes:


Hi,

I am trying to write a very simple function that accepts a string as input, and that returns a list of strings as output, having a seperate list item for every substring without a space.

Example:
input = "something very odd"
output = ("something" "very" "odd")

I tried to do this with the following function, but I can't understand why it is not working.

(defun parse(a)
(setq pos (or (position #\space a) -1) )
(cond ((= pos -1) (list a))
((> pos -1) (append
(parse (subseq a 0 pos))
(parse (subseq a (+ pos 1) (length a)))))))

Any comment is welcome!


Your design is basically correct but inefficient.

First you need to make pos a local variable

(let ((pos ..... some number of closing parens
(cond ....
^
|
`---- notice the indentation

Your editor will indent your code for you. In emacs its
ctrl-alt-h to set the region to the enclosing defun and
crtl-alt-\ to adjust the indentation.

If this makes it line up

(let ((pos ... (cond

you have one too many closing parentheses on the previous line

The other way to check is to position the cursor at the end
of the init forms

Position cursor here
|
|
V
(let ((pos ....))
^ ^
| |
These two get highlighted as the matching parentheses

In emacs you enable this with meta-x show-paren-mode

Next point is that the position function is carefully
designed to return either the position or Common Lisp's
false value, NIL, with the intention that the value is
directly usable as a boolean. Maybe I should say that the
other way round, Common Lisp's if operator is carefully
designed so that all numbers, including 0, count as
true. Thus the value returned by position is directly usable
as a boolean

(let ((pos ...))
(if pos
(code for when position is a number)
(code for when position is false)))

(append
(parse (subseq a 0 pos))
(parse (subseq a (+ pos 1) (length a))))

This could be

(cons
(subseq a 0 pos)
(parse (...as before...)))

Position finds the first matching item, so there is no need
to re-parse the leading subsequence.

The end argument to subseq is optional. You could just say

(subseq a (+ pos 1))

and that would also copy all the way to the end.

This brings up the efficiency issue. If there are many
separators the code copies the remaining characters many
times, so the run time is quadratic in the length of the
string when it ought to be linear.

The simplest solution is to add a numerical start argument
to parse, and use the :start key-word for position.

New programming languages often have annoying gaps.
Common Lisp was a unification effort, intended to unify
various previous dialects of Lisp. The upside is that Common
Lisp was an "old" language even when it was "new". The gaps
had all been discovered by programmers working on previous
dialects and Common Lisp ensured that they were all filled.
The ????-side is that it is a big language that combines
lots of useful features. Look at the examples that have been
posted using the LOOP macro.

That presents a problem to the autodidact. If you just
plunge in you are likely to spread yourself too thinly over
many different features and become frustrated. It is
probably best to follow a systematic tutorial. Graham's ANSI
Common Lisp is highly regarded as fast paced tutorial for
those already familiar with programming. (It is the book I
read to learn Common Lisp) It will be interesting to see if
Peter Seibel's impressive Practical Common Lisp

http://www.gigamonkeys.com/book/functions.html

suplants it.

Alan Crowe
Edinburgh
Scotland

Thanks a lot! That's what I call a valuable answer! ... think you showed some essential properties of functional programming, and Common Lisp in particular. I didn't realize that indentation could be that important.

I indeed plan to read Graham's book, which seems to be "the" common lisp book. I used Haskell some years ago, and was to optimistic in the idea that it wouldn't take that much time to do some elementary stuff in lisp. I know better now ...

regards,

wouter
.



Relevant Pages

  • Re: Newbie lisp problem: string to list of strings separated by space
    ... I am trying to write a very simple function that accepts a string as ... (parse (subseq a 0 pos)) ... dialects and Common Lisp ensured that they were all filled. ...
    (comp.lang.lisp)
  • Newbie lisp problem: string to list of strings separated by space
    ... I am trying to write a very simple function that accepts a string as input, and that returns a list of strings as output, having a seperate list item for every substring without a space. ... (parse (subseq a 0 pos)) ...
    (comp.lang.lisp)
  • Re: Reading and processing text
    ... (defun space-count (string) ... (let* ((char (char text i)) ... if it's not Common Lisp or Scheme it ... runtime performance, in programmer ...
    (comp.lang.lisp)
  • Re: Getting a number from a string
    ... > So I'm trying to use Common Lisp in place of Perl for some of my ... > This is trivial to do in Perl, where I can just coerce the string to a ... > But I'm at a loss as to how I'd do this in Common Lisp. ... So if there is anything that the REPL can do, you also can do it by ...
    (comp.lang.lisp)
  • Re: sending a format result to a string variable
    ... > string with a fill pointer. ... > with a fill pointer and use it for passing the format ... result, rather than printing, give it NIL as the output ... Also, Common Lisp is case-insensitive, so I would not ...
    (comp.lang.lisp)