From: Mark Carter
Subject: Newbie - request for code comments
Date: 
Message-ID: <d3c9c04.0310111005.14b9cb86@posting.google.com>
The discussion about python and lisp has lead me to give lisp another
tentative bash. So far, python is winning on the compactness and
readability stakes. Anyway, here goes ...

I have written a function which takes a list of strings, and replaces
target elements in it with new strings. Here's what I have:


(defun replace-strings (old-string new-string list-of-strings)
 (map 'list
      #'(lambda (x) (replace-string old-string new-string x))
      list-of-strings))

(defun replace-string (old-string new-string input-string)
  (if (string= old-string input-string)
      (values new-string)
    (values input-string)))


Everything works, but I am wondering if anyone had any comments on its
style.
Could it be simplified and/or have its clarity improved?

To my eyes, there looks to be something inelegant about having to
insert a lambda ... a bit "work-around'ish".

Maybe lisp would be neater if it had implicit list and argument
conversion. So I might define:
(defun silly-plus (arg1 arg2) (+ arg1 arg2))
and I could call it using
(silly-plus (1 2))
and lisp would be smart enough to know that I really meant:
(silly-plus 1 2)

(Or is there a way of doing it explicitly and neatly?)

From: Howard Ding <······@hading.dnsalias.com>
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <m3llrr5xfr.fsf@frisell.localdomain>
············@ukmail.com (Mark Carter) writes:

>
> (defun replace-strings (old-string new-string list-of-strings)
>  (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))
>
> (defun replace-string (old-string new-string input-string)
>   (if (string= old-string input-string)
>       (values new-string)
>     (values input-string)))
>

To do it along those lines, why not eliminate some of the excess verbiage:

(defun replace-strings (old-string new-string list-of-strings)
  (mapcar #'(lambda (x) (replace-string old-string new-string x))
          list-of-strings))

(defun replace-string (old-string new-string input-string)
  (if (string= old-string input-string)
      new-string
    input-string))

or perhaps use the built in function substitute instead, which already does
what you want:

(defun replace-strings (old-string new-string list-of-strings)
  (substitute new-string old-string list-of-strings :test #'string-equal))


> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)
>
> (Or is there a way of doing it explicitly and neatly?)

(apply #'+ '(1 2))

All pretty much untested, of course.

-- 
Howard Ding
<······@hading.dnsalias.com>
From: Kenny Tilton
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <vRYhb.71285$lZ6.11198971@twister.nyc.rr.com>
Mark Carter wrote:
> The discussion about python and lisp has lead me to give lisp another
> tentative bash.

Cool.

>... So far, python is winning on the compactness and
> readability stakes.

During my brief but intense foray into Python to port Cells to, of 
course, PyCells, I did notice that code looked very clean. But then that 
was an explicit design goal of Python, one pretty far up in the order of 
precedence. So you have to expect Python to be strong that way. Lisps 
design goals were a lot different (expressive power, reflection, 
interactivity), and naturally Lisp is strong on those.

  Anyway, here goes ...
> 
> I have written a function which takes a list of strings, and replaces
> target elements in it with new strings. Here's what I have:
> 
> 
> (defun replace-strings (old-string new-string list-of-strings)
>  (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))

    (mapcar (lambda (x) ..etc)

.... is a little more compact
> 
> (defun replace-string (old-string new-string input-string)
>   (if (string= old-string input-string)
>       (values new-string)
>     (values input-string)))

     (if (string= ...)
          new-string
       input-string)

... is a little more compact

> 
> 
> Everything works, but I am wondering if anyone had any comments on its
> style.
> Could it be simplified and/or have its clarity improved?

     (substitute new-string old-string list-of-strings :test 'string=)

Would that work? I am screwing up my head to see if your code does 
anything else, but I do not think so. Anyway, CL comes with a lot of 
built-in functions. You should setup a bookmark on the CL HyperSpec:

    http://www-2.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/FrontMatter/

> 
> To my eyes, there looks to be something inelegant about having to
> insert a lambda ... a bit "work-around'ish".
> 
> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)

In general (not for addition) one sometimes does:

    (silly-something '(1 2) '(a b))

Do those lists get flattened or treated as individual work units 
themselves? in the general case it is hard to guess when lists should be 
unpacked. I have a make-rectangle function that lets you supply two, 
three, or four arguments which then should be two points, a point and 
length and width, or all four bounds, but that is for my own consumption.


-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Pascal Costanza
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <bm9i9p$5go$1@newsreader2.netcologne.de>
Mark Carter wrote:

> The discussion about python and lisp has lead me to give lisp another
> tentative bash. So far, python is winning on the compactness and
> readability stakes. Anyway, here goes ...
> 
> I have written a function which takes a list of strings, and replaces
> target elements in it with new strings. Here's what I have:
> 
> 
> (defun replace-strings (old-string new-string list-of-strings)
>  (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))
> 
> (defun replace-string (old-string new-string input-string)
>   (if (string= old-string input-string)
>       (values new-string)
>     (values input-string)))
> 
> 
> Everything works, but I am wondering if anyone had any comments on its
> style.
> Could it be simplified and/or have its clarity improved?

Try this:

(defun replace-strings (old-string new-string list-of-strings)
   (loop for string in list-of-strings
         if (string= string old-string) collect new-string
         else collect string))

> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)
> 
> (Or is there a way of doing it explicitly and neatly?)

Try this:

(apply (function silly-plus) '(1 2))


Pascal
From: Coby Beck
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <bmaf9i$13dv$1@otis.netspace.net.au>
"Pascal Costanza" <········@web.de> wrote in message
·················@newsreader2.netcologne.de...
> (apply (function silly-plus) '(1 2))

you don't like #' ?  I find it better in every metric I use.  I would think
its better for newbies too, something to break up that "parenthetical
monotony" ;)
From: james anderson
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <3F8854D0.25454563@setf.de>
Mark Carter wrote:
> ...
> I have written a function which takes a list of strings, and replaces
> target elements in it with new strings. Here's what I have:
> 
> (defun replace-strings (old-string new-string list-of-strings)
>  (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))
> ...
> 
> Everything works, but I am wondering if anyone had any comments on its
> style.
> Could it be simplified and/or have its clarity improved?

why do you need a function for that? but that you appear to want to swtich the
order of the new and old values, you could just as well express the effect
directly as

? (substitute "asdf" "qwer" '("qwer" "1234" "1234" "qwer") :test #'string=)
("asdf" "1234" "1234" "asdf")

the sequence operators sustain many uses which may not be apparent until one
acquaints oneself with the workings of the :start :end :test, etc. keywords.

> 
> To my eyes, there looks to be something inelegant about having to
> insert a lambda ... a bit "work-around'ish".
> 
...
From: ·············@comcast.net
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <he2f1ien.fsf@comcast.net>
············@ukmail.com (Mark Carter) writes:

> The discussion about python and lisp has lead me to give lisp another
> tentative bash. So far, python is winning on the compactness and
> readability stakes. Anyway, here goes ...
>
> I have written a function which takes a list of strings, and replaces
> target elements in it with new strings. Here's what I have:
>
>
> (defun replace-strings (old-string new-string list-of-strings)
>  (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))
>
> (defun replace-string (old-string new-string input-string)
>   (if (string= old-string input-string)
>       (values new-string)
>     (values input-string)))
>
>
> Everything works, but I am wondering if anyone had any comments on its
> style.
> Could it be simplified and/or have its clarity improved?

Use the built-in sequence operators.

(defun replace-strings (old-string new-string list-of-strings)
  (substitute new-string old-string list-of-strings :test #'string-equal))

> To my eyes, there looks to be something inelegant about having to
> insert a lambda ... a bit "work-around'ish".

INELEGANT?!  LAMBDA RULES!  (but you don't need the #' in front of a lambda)

> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)
>
> (Or is there a way of doing it explicitly and neatly?)

(apply #'silly-plus '(1 2))

  or if you want n-ary:

(reduce #'silly-plus '(1 2 3 4))
From: Anton van Straaten
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <JW0ib.32233$mQ2.9137@newsread1.news.atl.earthlink.net>
Mark Carter wrote:
> To my eyes, there looks to be something inelegant about having to
> insert a lambda ... a bit "work-around'ish".

I think that perception comes from seeing lambda as just another feature on
a checklist, rather than a fundamental semantic building block in the
language.  An important point about Lisp is that it provides both the
low-level tools you need to construct higher-level constructs, as well as a
whole slew of high level constructs that already do what you need.  Most
languages lack the former capability.  Lambda is one of the low-level tools
that provides this capability, in conjunction with macros.  But lambda is
very useful at higher levels, also.

BTW, here's a version which takes the same basic approach as your version,
and is similar to Kenny's version, but avoids explicit lambdas:

(defun replace-strings (old-string new-string list-of-strings)

  (defun replace-string (str)
    (if (string= str old-string)
        new-string
        str))

  (mapcar #'replace-string list-of-strings))

There are still a couple of lambdas in there, they're just implicit in the
defuns.

Of course, the 'loop' or 'substitute' versions are simpler, in an easy
example like this.

--Anton
From: Kenny Tilton
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <Ue2ib.71309$lZ6.11327475@twister.nyc.rr.com>
Anton van Straaten wrote:

> Mark Carter wrote:
> 
>>To my eyes, there looks to be something inelegant about having to
>>insert a lambda ... a bit "work-around'ish".
> 
> 
> I think that perception comes from seeing lambda as just another feature on
> a checklist, rather than a fundamental semantic building block in the
> language.  An important point about Lisp is that it provides both the
> low-level tools you need to construct higher-level constructs, as well as a
> whole slew of high level constructs that already do what you need.  Most
> languages lack the former capability.  Lambda is one of the low-level tools
> that provides this capability, in conjunction with macros.  But lambda is
> very useful at higher levels, also.
> 
> BTW, here's a version which takes the same basic approach as your version,
> and is similar to Kenny's version, but avoids explicit lambdas:
> 
> (defun replace-strings (old-string new-string list-of-strings)
> 
>   (defun replace-string (str)
>     (if (string= str old-string)
>         new-string
>         str))
> 
>   (mapcar #'replace-string list-of-strings))

Sweet. But if one has done C and had to stop in mid brainstorm to write 
(and declare in C++) a helper funtion outside one's code stream and then 
take it's address, one rejoiced at discovering one could just toss off a 
function object on the fly with lambda. We all just wish it had a macro 
character, as does QUOTE. :) Well, I could always write a macro (but not 
a function!) and shorten the name.  Hmmmm. :)

Btw, the OP, if he likes your version above, might also like:

(defun replace-strings (old new list)
    (flet ((repl$ (s) (if (string= s old) new s)))
        (mapcar 'repl list)))

But it is better to wait until we have an example not covered by an 
existing language function before fussing too much over versions.

kenny

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Anton van Straaten
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <pO4ib.21024$Eo2.16415@newsread2.news.atl.earthlink.net>
Kenny Tilton wrote:
> Sweet. But if one has done C and had to stop in mid brainstorm to write
> (and declare in C++) a helper funtion outside one's code stream and then
> take it's address, one rejoiced at discovering one could just toss off a
> function object on the fly with lambda.

Yes.  But one of the points I was illustrating, obliquely, was that the
explicit lambda in the OP's example was only needed because the helper
function wasn't in the original function's scope.  Moving the helper
function into that scope allowed that lambda to be eliminated entirely.

> We all just wish it had a macro
> character, as does QUOTE. :) Well, I could always write a macro (but not
> a function!) and shorten the name.  Hmmmm. :)

I defined a single-letter macro (L) for that a long, long time ago, which
includes a form that takes a single argument, so no parens needed.  It's so
abbreviated, though, that I never use it in code intended for public
consumption.  :)

> Btw, the OP, if he likes your version above, might also like:
>
> (defun replace-strings (old new list)
>     (flet ((repl$ (s) (if (string= s old) new s)))
>         (mapcar 'repl list)))

Yeah, I'm used to a 'define' form which respects lexical boundaries... :)

> But it is better to wait until we have an example not covered by an
> existing language function before fussing too much over versions.

I don't really agree.  People often tend to focus on small examples, partly
because they're easier to talk about than bigger examples, such as some of
the macros people were posting in the recent Python thread.  Small examples
often duplicate some functionality that's available some other way.  I treat
the small examples as something that you can, and should, extrapolate from.
Of course, the danger is that people take the small examples too literally,
and wonder why anyone would write code that way.  For example, in this case,
a named helper function is unnecessary; but if you had a situation where the
same helper was needed more than once, then naming it would make sense, and
the example suddenly becomes quite appropriate.

Anton
From: Kenny Tilton
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <q35ib.72051$lZ6.11413163@twister.nyc.rr.com>
Anton van Straaten wrote:
> ..  Small examples
> often duplicate some functionality that's available some other way.  I treat
> the small examples as something that you can, and should, extrapolate from.

My unstated concern was that the newbie was looking for help not with 
making something work but on how it could be done most concisely. If he 
was asking "why would I ever use flet?", it would be fine to re-invent 
subsitute using flet as I did in one version. But when the context is 
"how concise or powerful is the language", we shouldn't write extra code 
until it is called for.

Part of Lisp's conciseness comes from CLs huge spec, you know, and the 
versatility of the built-in data structures like lists and hash-tables. 
Given all that built-in functionality, it could be a while before the OP 
comes up with something that cannot be handled in three or four lines. 
That in itself answers at least one question he has as he looks again at 
Lisp. Certainly it is the first question raised on c.l.l. (And he seems 
to know his way around programming already.)

When he gets beyond what the built-in offers to something meatier, we'll 
see more Lisp, but no more than necessary. Which is a good idea anyway, 
unless (as is not the case here) we are trying to teach something about 
the programming per se.

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Anton van Straaten
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <lt5ib.21459$Eo2.16322@newsread2.news.atl.earthlink.net>
Kenny Tilton wrote:
>
>
> Anton van Straaten wrote:
> > ..  Small examples
> > often duplicate some functionality that's available some other way.  I
treat
> > the small examples as something that you can, and should, extrapolate
from.
>
> My unstated concern was that the newbie was looking for help not with
> making something work but on how it could be done most concisely.

I made sure, before responding, that others had already provided answers
like 'loop' and 'substitute', and I pointed out in my post that these were
simpler solutions in this case.

> If he was asking "why would I ever use flet?", it would be fine to
re-invent
> subsitute using flet as I did in one version. But when the context is
> "how concise or powerful is the language", we shouldn't write extra code
> until it is called for.

It was "called for" by his use of map with a lambda, and wondering about the
need for a lambda in that case.

> When he gets beyond what the built-in offers to something meatier, we'll
> see more Lisp, but no more than necessary. Which is a good idea anyway,
> unless (as is not the case here) we are trying to teach something about
> the programming per se.

As I see it, learning about "the programming per se" is more important,
particularly for someone who "seems to know his way around programming
already."

Anton
From: Frode Vatvedt Fjeld
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <2hbrsmsleb.fsf@vserver.cs.uit.no>
Kenny Tilton <·······@nyc.rr.com> writes:

> Btw, the OP, if he likes your version above, might also like:

> (defun replace-strings (old new list)
>     (flet ((repl$ (s) (if (string= s old) new s)))
>         (mapcar 'repl list)))

The nested defun has already been rightfully debunked, but there is
also a problem with the example above (at least if CL newcomers are
reading this). Symbols are funcallable in Common Lisp, but they are
only resolved in the global (function) environment. So this should
read:

  (defun replace-strings (old new list)
    (flet ((repl (s) (if (string= s old) new s)))
      (mapcar #'repl list)))

It is precisely the job of the function operator to look up its
argument in the lexical environment.

-- 
Frode Vatvedt Fjeld
From: Coby Beck
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <bmaflb$171t$1@otis.netspace.net.au>
"Anton van Straaten" <·····@appsolutions.com> wrote in message
·························@newsread1.news.atl.earthlink.net...
> BTW, here's a version which takes the same basic approach as your version,
> and is similar to Kenny's version, but avoids explicit lambdas:
>
> (defun replace-strings (old-string new-string list-of-strings)
>
>   (defun replace-string (str)
>     (if (string= str old-string)
>         new-string
>         str))
>
>   (mapcar #'replace-string list-of-strings))
>
> There are still a couple of lambdas in there, they're just implicit in the
> defuns.

You're probably just making a point, but I can think of no good reason for
using defun inside of a defun (with the obvious exception of writing code
programmatically).
From: Anton van Straaten
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <bx4ib.32472$mQ2.31170@newsread1.news.atl.earthlink.net>
Coby Beck wrote:
> "Anton van Straaten" <·····@appsolutions.com> wrote in message
> ·························@newsread1.news.atl.earthlink.net...
> > BTW, here's a version which takes the same basic approach as your
version,
> > and is similar to Kenny's version, but avoids explicit lambdas:
> >
> > (defun replace-strings (old-string new-string list-of-strings)
> >
> >   (defun replace-string (str)
> >     (if (string= str old-string)
> >         new-string
> >         str))
> >
> >   (mapcar #'replace-string list-of-strings))
> >
> > There are still a couple of lambdas in there, they're just implicit in
the
> > defuns.
>
> You're probably just making a point, but I can think of no good reason for
> using defun inside of a defun (with the obvious exception of writing code
> programmatically).

Put it down to mindless translation of a Scheme idiom.  I should have used
FLET.
From: Mark Carter
Subject: Re: Newbie - request for code comments (thanks)
Date: 
Message-ID: <d3c9c04.0310120531.6661f675@posting.google.com>
············@ukmail.com (Mark Carter) wrote in message news:<···························@posting.google.com>...
> I have written a function which takes a list of strings, and replaces

Wow - good response. Thanks. Your feedback has been very useful. I am
using Common Lisp for the PC. As I am just giving Lisp a spin, I
obviously haven't forked out on a commercial system. This means that
the documentation that I have been able to find is, shall we say,
somewhat compact. It will be some time before I've figured out what
exactly is going on. So having feedback on what I am trying to do has
been a real help.

The program that I was writing was small - it created a static weblog
front sheet. Interestingly, it seems that I will now be able to tweak
it so that it uses no (explicit) iterations or conditionals at all;
just a succession of filters. This should make the program
conceptually very easy to understand, because the data flows from top
to bottom, all in a straight line.

The chances of me actually being allowed to write deliverable code
using Lisp are infinitesimally small, but I might stick with it for a
while to see if it can displace python for my ordinary scripting jobs.

I think that python programmers are natural candidates for trying out
Lisp, on the basis that they are likely to be people who don't mind
experimenting with something not-in-the-mainstream (can I say that?)
if they think that there is a better way of doing things.

For my sins, I get paid to write in Visual Basic for Applications
*groan*. My employers are engineers, not programmers, and it's
difficult to explain to them that no, VBA is not necessarily the best
language ever invented. "But the clients wont let you install software
on their machine", they state. I kid you not!

Anyone interested in knowing more about my background (hey, it could
happen), can look here:
www.markcarter.me.uk/employment/mcarter.html

Some departing shots:
* I see that wxLisp (Lisp bindings for wxWindows - a cross-platform
GUI) has been started on Sourceforge. Now there's an idea!
* hyphens in function/variable names: great stuff! Now I don't have to
use the shift key.
From: Howard Ding <······@hading.dnsalias.com>
Subject: Re: Newbie - request for code comments (thanks)
Date: 
Message-ID: <m3pth27f0x.fsf@frisell.localdomain>
············@ukmail.com (Mark Carter) writes:


> Wow - good response. Thanks. Your feedback has been very useful. I am
> using Common Lisp for the PC. As I am just giving Lisp a spin, I
> obviously haven't forked out on a commercial system. This means that
> the documentation that I have been able to find is, shall we say,
> somewhat compact. It will be some time before I've figured out what
> exactly is going on. So having feedback on what I am trying to do has
> been a real help.
>

The Hyperspec is quite readable, and is freely downloadable from
places such as:

http://www.lispworks.com/reference/HyperSpec/index.html

For example, for your problem I was sure there was a function that must
do it directly, but I couldn't remember exactly what it was, so I
consulted the sequences part of the HyperSpec and checked out replace
and then substitute as two logical possibilities.  Done.

-- 
Howard Ding
<······@hading.dnsalias.com>
From: Kenny Tilton
Subject: Re: Newbie - request for code comments (thanks)
Date: 
Message-ID: <aYdib.72944$lZ6.11563695@twister.nyc.rr.com>
Mark Carter wrote:

> I think that python programmers are natural candidates for trying out
> Lisp,...

Send them on over, we need help on various open s/w projects.

>... on the basis that they are likely to be people who don't mind
> experimenting ...

Yes, I have long considered the enthusiasm for Perl, Python, and Ruby 
good signs for wider adoption of the Lisp family; people using those are 
the early adopters, the easisest folks to reach with surprising new 
technology (a strange way to characterize a 45 year-old language, but so 
it is).

>...with something not-in-the-mainstream (can I say that?)

Since I regulalrly run into comp sci undergrads who have never heard of 
Lisp, I think you can say that. :)

kenny

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Coby Beck
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <bmaf1r$126e$1@otis.netspace.net.au>
"Mark Carter" <············@ukmail.com> wrote in message
································@posting.google.com...
> The discussion about python and lisp has lead me to give lisp another
> tentative bash. So far, python is winning on the compactness and
> readability stakes. Anyway, here goes ...
>
> I have written a function which takes a list of strings, and replaces
> target elements in it with new strings. Here's what I have:

CL-USER 13 >
(defun replace-strings (new old seq &key (test #'string=))
  (substitute new old seq :test test))
REPLACE-STRINGS

CL-USER 14 > (replace-strings "easy" "hard" (list "how" "hard" "was"
"that?"))
("how" "easy" "was" "that?")

CL-USER 15 > (replace-strings "easy" "hard" (list "how" "HARD" "was"
"that?") :test #'string-equal)
("how" "easy" "was" "that?")

CL-USER 16 > (replace-strings "easy" "hard" (list "how" "HARD" "was"
"that?"))
("how" "HARD" "was" "that?")

CL-USER 17 > (defvar foo (make-array '(4) :initial-element "hard"))
FOO

CL-USER 18 > (replace-strings "easy" "hard" foo)
#("easy" "easy" "easy" "easy")

CL-USER 19 >
(defun replace-strings (new old seq &rest keys &key (test #'string=)
                            &allow-other-keys)
  (apply #'substitute new old seq :test test keys))
REPLACE-STRINGS

CL-USER 20 > (replace-strings "easy" "hard" foo :count 2)
#("easy" "easy" "hard" "hard")


> Everything works, but I am wondering if anyone had any comments on its
> style.
>
> (defun replace-strings (old-string new-string list-of-strings)
>  (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))

I think mapcar is more normal rather than map 'list.  Personally,
replace-string is not so exciting as to get a seperate definition from
replace-strings and since you are using a lambda already, why not just put
all the functionality in there?

> (defun replace-string (old-string new-string input-string)
>   (if (string= old-string input-string)
>       (values new-string)
>     (values input-string)))

using values when there is exactly one value is unnecessary.  #'string= is
not the only string comparison one might want to use, so the "lisp way"
would be to have a :test keyword arg (which can default to #'string= ).

> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)

You don't really want this.

> (Or is there a way of doing it explicitly and neatly?)

(apply #'silly-plus '(1 2))

Apply is even better than this in that you can do:
(apply #'+ 1 2 3 '(4 5)) ==> 15

If you really end up in a program not knowing if your arguments are listed
or not you could always do something like:
(if (listp arg)
    (apply func arg)
   (funcall func arg))

but it would be better if you located and fixed the design fault! ;)

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Alan Crowe
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <86zng6czho.fsf@cawtech.freeserve.co.uk>
Mark Carter requested comments on his code:
> (defun replace-strings (old-string new-string list-of-strings)
>   (map 'list
>       #'(lambda (x) (replace-string old-string new-string x))
>       list-of-strings))
>
> (defun replace-string (old-string new-string input-string)
>   (if (string= old-string input-string)
>      (values new-string)
>    (values input-string)))

He has received a variety replies, based on different
assumptions about which aspects of his code are to be taken
literally and which exemplify wider possibilities.

My initial reaction was that we were being asked how to
avoid the second defun. Easy:

(defun replace-strings (old-string new-string list-of-strings)
    (mapcar #'(lambda(candidate-string)
		(if  (string= candidate-string old-string)
		    new-string
		  candidate-string))
	    list-of-strings))

Whoops. Here are my second thoughts.

Consider a piece of mathematics, in which the mathematician
is calling a,b,c his parameters and x,y his variables

   2                 2
a x   +  b xy  +  c y 

So he codes up

(defun conic (a b c x y)
    (+ (* a x x)
       (* b x y)
       (* c y y)))

Next he wants a routine map-conic to run his conic function
over lists of variables for fixed values of the parameters.
The question is: how do you pass the fixed values of the
parameters into the function that is the functional argument
to mapcar.

Standard answer, anonymous lambda

(defun map-conic (a b c x-list y-list)
    (mapcar #'(lambda(x y)(conic a b c x y))
	    x-list
	    y-list))

Nice use of flet

(defun map-conic (a b c x-list y-list)
    (flet ((conic (x y)(conic a b c x y)))
    (mapcar #'conic
	    x-list
	    y-list)))

where |labels| would have required me to come up with a new
name such as conic-with-the-parameters-filled-in 

A third possibility is using special variables.

(defun conic (x y)
    (+ (* a x x)
       (* b x y)
       (* c y y)))

(defun map-conic (a b c x-list y-list)
    (declare (special a b c))
    (mapcar #'conic
	    x-list
	    y-list))

(map-conic 2 3 5 '(10 1 1) '(1 10 1))
=> (235 532 10)

Notice that I am correctly writing "a" not "*a*"
*a* is a convention for special variables created with
defvar or defparameter, because they are pervasively special
which breaks subsequent closures. Not what I've done here.

Using special variables like this really depends on where
a,b, and c fit into the overall structure of your
program. Obviously they fit in differently from x and y,
that is what this is all about, but how differently? Should
they have lexical scope or dynamic scope? You chose.

> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)
>
> (Or is there a way of doing it explicitly and neatly?)

I assume that Mark is asking for more than this 

(funcall #'+ 1 2 3 4) => 10
(apply #'+ 1 2 '(3 4)) => 10

This is a reasonable idea for functions that take numerical
arguments, because it is plain enough when you have a list
instead of a number and thus want auto-conversion.

So maybe you want

(defun make-auto-convert(function-name)
    (let ((original-function (symbol-function function-name)))
      (setf (symbol-function function-name)
	    #'(lambda(first &rest list)
		(cond ((numberp first)
		       (apply original-function first list))
		      ((and (null list)(listp first))
		       (apply original-function first))
		      (t (error "This is getting out of control")))))))

which lets you go round turning functions into their
auto-convert equivalents where you consider it appropriate

(defun plus(x y)(+ x y))
(make-auto-convert 'plus)
(plus 5 7) => 12
(plus '(5 7) => 12

; change definition of map-conic
(defun map-conic (a b c xy-list)
    (declare (special a b c))
    (mapcar #'conic xy-list))

(make-auto-convert 'conic)
(map-conic 2 3 4 '((10 1)(1 10)(10 0.1)))
=> (234 432 203.04)

I love all this cool stuff, but I fear that I'm getting
carried way and should just have written

(defun conic (a b c x y)
    (+ (* a x x)
       (* b x y)
       (* c y y)))

(defun map-conic (a b c xy-list)
  (mapcar #'(lambda(xy-together)
	      (apply #'conic a b c xy-together))
	  xy-list))

Alan Crowe
From: Steve Long
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <BBC34293.509D%sal6741@hotmail.com>
On 10/11/2003 10:05 AM, in article
···························@posting.google.com, "Mark Carter"
<············@ukmail.com> wrote:

> The discussion about python and lisp has lead me to give lisp another
> tentative bash. So far, python is winning on the compactness and
> readability stakes. Anyway, here goes ...
> 
> I have written a function which takes a list of strings, and replaces
> target elements in it with new strings. Here's what I have:
> 
> 
> (defun replace-strings (old-string new-string list-of-strings)
> (map 'list
>     #'(lambda (x) (replace-string old-string new-string x))
>     list-of-strings))
> 
> (defun replace-string (old-string new-string input-string)
> (if (string= old-string input-string)
>     (values new-string)
>   (values input-string)))
> 
> 
> Everything works, but I am wondering if anyone had any comments on its
> style.
> Could it be simplified and/or have its clarity improved?
> 
> To my eyes, there looks to be something inelegant about having to
> insert a lambda ... a bit "work-around'ish".
> 
> Maybe lisp would be neater if it had implicit list and argument
> conversion. So I might define:
> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> and I could call it using
> (silly-plus (1 2))
> and lisp would be smart enough to know that I really meant:
> (silly-plus 1 2)
> 
> (Or is there a way of doing it explicitly and neatly?)

General string-within-string substitution  ... this has been asked and
answered many times. I have modified one of those answers posted several
weeks ago to include a case sensitivity parameter:


(defun replace-string (old new str &key (ignore-case nil))
    (do* ((test   (if ignore-case #'char-equal #'char=))
          (start  0
                  (1+ p))
          (p      (when (< start (length str))
                    (search old str :start2 start :test test))
                  (when (< start (length str))
                    (search old str :start2 start :test test)))
          (newstr nil))
        ((null p) 
         (progn 
           (push (subseq str start p) newstr)
           (apply (function concatenate) 'string (nreverse newstr))))
     (push (subseq str start p) newstr)
     (push new newstr)))

Python is a neat little scripting tool, but is not my tool of choice for
complicated OO systems.
From: Steve Long
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <BBC3475F.51CD%sal6741@hotmail.com>
On 10/27/2003 9:42 PM, in article ·····················@hotmail.com, "Steve
Long" <·······@hotmail.com> wrote:

> On 10/11/2003 10:05 AM, in article
> ···························@posting.google.com, "Mark Carter"
> <············@ukmail.com> wrote:
> 
>> The discussion about python and lisp has lead me to give lisp another
>> tentative bash. So far, python is winning on the compactness and
>> readability stakes. Anyway, here goes ...
>> 
>> I have written a function which takes a list of strings, and replaces
>> target elements in it with new strings. Here's what I have:
>> 
>> 
>> (defun replace-strings (old-string new-string list-of-strings)
>> (map 'list
>>     #'(lambda (x) (replace-string old-string new-string x))
>>     list-of-strings))
>> 
>> (defun replace-string (old-string new-string input-string)
>> (if (string= old-string input-string)
>>     (values new-string)
>>   (values input-string)))
>> 
>> 
>> Everything works, but I am wondering if anyone had any comments on its
>> style.
>> Could it be simplified and/or have its clarity improved?
>> 
>> To my eyes, there looks to be something inelegant about having to
>> insert a lambda ... a bit "work-around'ish".
>> 
>> Maybe lisp would be neater if it had implicit list and argument
>> conversion. So I might define:
>> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
>> and I could call it using
>> (silly-plus (1 2))
>> and lisp would be smart enough to know that I really meant:
>> (silly-plus 1 2)
>> 
>> (Or is there a way of doing it explicitly and neatly?)
> 
> General string-within-string substitution  ... this has been asked and
> answered many times. I have modified one of those answers posted several
> weeks ago to include a case sensitivity parameter:
> 
> 
> (defun replace-string (old new str &key (ignore-case nil))
>   (do* ((test   (if ignore-case #'char-equal #'char=))
>         (start  0
>                 (1+ p))
>         (p      (when (< start (length str))
>                   (search old str :start2 start :test test))
>                 (when (< start (length str))
>                   (search old str :start2 start :test test)))
>         (newstr nil))
>       ((null p) 
>        (progn 
>          (push (subseq str start p) newstr)
>          (apply (function concatenate) 'string (nreverse newstr))))
>    (push (subseq str start p) newstr)
>    (push new newstr)))
> 
> Python is a neat little scripting tool, but is not my tool of choice for
> complicated OO systems.
> 

Alternatively, performing collection ops at each step...

(defun string-substitute (old-str new-str string &key (ignore-case? nil))
  (do* ((test        (if ignore-case? #'char-equal #'char=))
        (len-old-str (length old-str))
        (string-out  ""
                     (concatenate
                      'string
                      string-out
                      (subseq str 0 p)
                      new-str))
        (str         string
                     (subseq str (+ p len-old-str)))
        (p           (search old-str str :test test)
                     (search old-str str :test test)))
       ((null p) (concatenate 'string string-out str))))
From: Gareth McCaughan
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <87n0bleq8s.fsf@g.mccaughan.ntlworld.com>
Steve Long wrote:

[Mark Carter:]
>>> I have written a function which takes a list of strings, and replaces
>>> target elements in it with new strings. Here's what I have:
>>> 
>>> 
>>> (defun replace-strings (old-string new-string list-of-strings)
>>> (map 'list
>>>     #'(lambda (x) (replace-string old-string new-string x))
>>>     list-of-strings))
>>> 
>>> (defun replace-string (old-string new-string input-string)
>>> (if (string= old-string input-string)
>>>     (values new-string)
>>>   (values input-string)))
>>> 
>>> 
>>> Everything works, but I am wondering if anyone had any comments on its
>>> style.
>>> Could it be simplified and/or have its clarity improved?
>>> 
>>> To my eyes, there looks to be something inelegant about having to
>>> insert a lambda ... a bit "work-around'ish".
>>> 
>>> Maybe lisp would be neater if it had implicit list and argument
>>> conversion. So I might define:
>>> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
>>> and I could call it using
>>> (silly-plus (1 2))
>>> and lisp would be smart enough to know that I really meant:
>>> (silly-plus 1 2)
>>> 
>>> (Or is there a way of doing it explicitly and neatly?)

[Steve:]
>> General string-within-string substitution  ... this has been asked and
>> answered many times. I have modified one of those answers posted several
>> weeks ago to include a case sensitivity parameter:
>> 
>> (defun replace-string (old new str &key (ignore-case nil))
>>   (do* ((test   (if ignore-case #'char-equal #'char=))
>>         (start  0
>>                 (1+ p))
>>         (p      (when (< start (length str))
>>                   (search old str :start2 start :test test))
>>                 (when (< start (length str))
>>                   (search old str :start2 start :test test)))
>>         (newstr nil))
>>       ((null p) 
>>        (progn 
>>          (push (subseq str start p) newstr)
>>          (apply (function concatenate) 'string (nreverse newstr))))
>>    (push (subseq str start p) newstr)
>>    (push new newstr)))
...
> (defun string-substitute (old-str new-str string &key (ignore-case? nil))
>   (do* ((test        (if ignore-case? #'char-equal #'char=))
>         (len-old-str (length old-str))
>         (string-out  ""
>                      (concatenate
>                       'string
>                       string-out
>                       (subseq str 0 p)
>                       new-str))
>         (str         string
>                      (subseq str (+ p len-old-str)))
>         (p           (search old-str str :test test)
>                      (search old-str str :test test)))
>        ((null p) (concatenate 'string string-out str))))

I have three issues with these suggested functions.

  1 They are longer than Mark's original code.
  2 They are inefficient, taking time of order N^2,
    where Mark's original code was of order N.
  3 They are solving a different problem.

-- 
Gareth McCaughan
.sig under construc
From: Jon S. Anthony
Subject: Re: Newbie - request for code comments
Date: 
Message-ID: <m3vfq9wey5.fsf@rigel.goldenthreadtech.com>
Steve Long <·······@hotmail.com> writes:

> > ···························@posting.google.com, "Mark Carter"
> > <············@ukmail.com> wrote:
> > 
> >> Maybe lisp would be neater if it had implicit list and argument
> >> conversion. So I might define:
> >> (defun silly-plus (arg1 arg2) (+ arg1 arg2))
> >> and I could call it using
> >> (silly-plus (1 2))
> >> and lisp would be smart enough to know that I really meant:
> >> (silly-plus 1 2)

On this specific point, what does the above do for you that

(defun silly-plus (&rest args) (apply #'+ args))

(silly-plus 1 2)

doesn't do for you?


/Jon