(concatenate 'string "foo" (a-string-returning-function) "baz"))
I do this sort of thing a lot, and I'm tired of looking at concatenate
'string everywhere. So I thought it'd be nice to have something with
a short name, like strcat (at least I didn't call it StrCat. Would
str-cat be more Lispy?) I want the name short, because that helps
keep the code small and avoid having to have excess carriage returns
everywhere
Anyways, it's easy to define as a macro:
(defmacro strcat (&rest args)
`(concatenate 'string ,@args))
So my question is, is there a way to define this as a function rather
than a macro?
Cheers,
rif
(defun strcat (&rest args)
(apply #'concatenate 'string args))
Looks good to me. Or am I missing something?
-Tim
> I can concatenate strings using
>
> (concatenate 'string "foo" (a-string-returning-function) "baz"))
>
> I do this sort of thing a lot, and I'm tired of looking at concatenate
> 'string everywhere. So I thought it'd be nice to have something with
> a short name, like strcat (at least I didn't call it StrCat. Would
> str-cat be more Lispy?) I want the name short, because that helps
> keep the code small and avoid having to have excess carriage returns
> everywhere
Personally I would name it STRING-CONCAT or some such, but that's only
me and I'm having a lot of trouble fitting my code into 80 columns. :)
> Anyways, it's easy to define as a macro:
>
> (defmacro strcat (&rest args)
> `(concatenate 'string ,@args))
>
>
> So my question is, is there a way to define this as a function rather
> than a macro?
>
Yes there is! In fact, it will be even simpler than your macro:
(defun strcat (&rest args)
(apply #'concatenate 'string args))
If you are not familiar with APPLY, check out CLtL2 or CLHS, since
both do a far better at explaining its use than I am able to.
Hope that helps!
Richard.
P.S. Personally I would leave it as a macro, since you're not doing
anything but rewriting the way a function is called.
--
"I know not with what weapons World War III will be fought, but World War
IV will be fought with sticks and stones." -- Albert Einstein
Well, short names in general are not very Lispy. Except for some of the
primitives that are used extremely frequently (DEFUN, CAR, CONS), most Lisp
functions are words spelled out in full. In Zetalisp this function was
called STRING-APPEND.
>Anyways, it's easy to define as a macro:
>
>(defmacro strcat (&rest args)
> `(concatenate 'string ,@args))
>
>So my question is, is there a way to define this as a function rather
>than a macro?
(defun strcat (&rest args)
(apply #'concatenate 'string args))
--
Barry Margolin, bar...@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.
But that should have told you something. You should perhaps look into
Common Lisp's support for string-streams.
--
Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
Hm then I would declare it inline.
ciao,
Jochen
> I can concatenate strings using
>
> (concatenate 'string "foo" (a-string-returning-function) "baz"))
Yep, you can. One thing you might consider is using the functional
programming utility "curry". Here's a simple definition:
(defun curry (fn &rest args)
(if (null args)
fn
(let ((first (first args)))
(curry #'(lambda (&rest args) (apply fn first args))
(rest args)))))
Now you can say:
(let ((string-cat (curry #'concatenate 'string)))
(funcall string-cat "foo" "bar" "baz"))
It's not the most efficient way of doing this, but...
> I do this sort of thing a lot, and I'm tired of looking at concatenate
> 'string everywhere.
... you're obviously not concerned with efficiency. That, or you have
yet to discover WITH-OUTPUT-TO-STRING.
> So I thought it'd be nice to have something with a short name, like
> strcat (at least I didn't call it StrCat. Would str-cat be more
> Lispy?) I want the name short, because that helps keep the code
> small and avoid having to have excess carriage returns everywhere
Using abbreviations in global names is generally considered a bad
thing. Notice how few CL functions use them ... and those are only
the old ones, before the lesson was learned.
--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
Shouldn't it be (apply #'curry #'(lambda ...) (rest args))?
BTW, the way this definition reuses variable and function names reminds me
of the old PL/I joke:
IF IF = IF
THEN THEN = THEN;
ELSE ELSE = ELSE;
Let's hear it for languages without reserved words! :)
>Now you can say:
>
> (let ((string-cat (curry #'concatenate 'string)))
> (funcall string-cat "foo" "bar" "baz"))
>
>It's not the most efficient way of doing this, but...
You could also do:
(defun string-cat (&rest strings)
(reduce #'(lambda (s1 s2) (concatenate 'string s1 s2)) strings))
> But that should have told you something. You should perhaps look into
> Common Lisp's support for string-streams.
>
Thanks. I will check this out.
rif
> rif <r...@mit.edu> writes:
>
> > I can concatenate strings using
> >
> > (concatenate 'string "foo" (a-string-returning-function) "baz"))
>
> Yep, you can. One thing you might consider is using the functional
> programming utility "curry". Here's a simple definition:
>
> (defun curry (fn &rest args)
> (if (null args)
> fn
> (let ((first (first args)))
> (curry #'(lambda (&rest args) (apply fn first args))
> (rest args)))))
>
> Now you can say:
>
> (let ((string-cat (curry #'concatenate 'string)))
> (funcall string-cat "foo" "bar" "baz"))
>
> It's not the most efficient way of doing this, but...
Indeed ;-) The only thing I miss since I turned my back to *ML
and came back to Lisp is currying; here is my version of CURRY:
(defmacro curry (f &rest curry-args)
(let ((args (gensym "ARGS"))
(fun (gensym "FUN"))
(curries (mapcar (lambda (arg)
(declare (ignore arg))
(gensym))
curry-args)))
`(let ((,fun ,f)
,@(mapcar #'list curries curry-args))
(lambda (&rest ,args)
(declare (dynamic-extent ,args))
(apply ,fun ,@curries ,args)))))
CL-USER 143 > (map nil (curry #'format t "~&~D ~A")
'(1 2 3)
'(foo bar baz))
1 FOO
2 BAR
3 BAZ
NIL
Regards,
--
Nils Gösche
Ask not for whom the <CONTROL-G> tolls.
PGP key ID #xD26EF2A0
> Using abbreviations in global names is generally considered a bad
> thing. Notice how few CL functions use them ... and those are only
But conversely, CL is a language which encourages you to create your
own domain-specific language on top of it, and perhaps it's reasonable
when creating a language that the shorter words should correspond to
the most often-used concepts.
After all, it seems on the whole, a bit pointless to create an
alternative to (concatenate 'string ...) on the grounds that it's
excessively long, unless the replacement is going to be significantly
shorter.
(That said, I agree with the other comments here that string-streams
are probably a better idea in this case anyway)
-dan
--
http://ww.telent.net/cliki/ - Link farm for free CL-on-Unix resources
Thank you for posting this question rif! And thank you everyone who offered
your thoughts and advice about this.
klw
"rif" <r...@mit.edu> wrote in message
news:wj0znsc...@five-percent-nation.mit.edu...
It is better to use functions when you can, because functions are far
more flexible than macros: you can apply, funcall, reduce, map, and
generally pass them around. If you want to avoid the overhead of the
function call, instead of using a macro use an inline function, as
Jochen points out.
--
; Matthew Danish <mda...@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
I think a good general rule of thumb is if it is evaluating all its
arguments, it is not a macro.
ie
(defmacro strcat (@rest strings)
`(concatenate 'string ,strings))
--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
> In article <xcvd6p7...@apocalypse.OCF.Berkeley.EDU>,
> Thomas F. Burdick <t...@apocalypse.OCF.Berkeley.EDU> wrote:
> >rif <r...@mit.edu> writes:
> >
> >> I can concatenate strings using
> >>
> >> (concatenate 'string "foo" (a-string-returning-function) "baz"))
> >
> >Yep, you can. One thing you might consider is using the functional
> >programming utility "curry". Here's a simple definition:
> >
> > (defun curry (fn &rest args)
> > (if (null args)
> > fn
> > (let ((first (first args)))
> > (curry #'(lambda (&rest args) (apply fn first args))
> > (rest args)))))
>
> Shouldn't it be (apply #'curry #'(lambda ...) (rest args))?
Oops, that's what I get for coding directly in my post. The actual
CURRY-LEFT and CURRY-RIGHT functions (and accompanying compiler
macros) I use are a little less obvious, and I was just trying to get
the point across.
> BTW, the way this definition reuses variable and function names reminds me
> of the old PL/I joke:
>
> IF IF = IF
> THEN THEN = THEN;
> ELSE ELSE = ELSE;
>
> Let's hear it for languages without reserved words! :)
Between my working on compiler stuff, and the CL interpreter I
recently wrote (in debugging, but coming in a public and liberally
licenced form soon), I'm slightly worried that I'm more comfortable
with two namespaces and tight scoping than most people. I noticed
that over the last year or two, I've been doing even more of this than
I used to.
> >Now you can say:
> >
> > (let ((string-cat (curry #'concatenate 'string)))
> > (funcall string-cat "foo" "bar" "baz"))
> >
> >It's not the most efficient way of doing this, but...
>
> You could also do:
>
> (defun string-cat (&rest strings)
> (reduce #'(lambda (s1 s2) (concatenate 'string s1 s2)) strings))
Wow, now that's cons-y :)
So I investigated a bit, and it seems to me (please correct me if I'm
wrong) that string-streams are the right solution if what I'm doing is
building up a single string using a large number of concatenate
operations. In my situation, what's actually happening is that once
or twice per function (in many functions), I need to take a base file
name and add an extension to the filename (not always the same
extnsions(s)), so I don't thing that string-streams help here.
rif
> In my situation, what's actually happening is that once
> or twice per function (in many functions), I need to take a base file
> name and add an extension to the filename (not always the same
> extnsions(s)), so I don't thing that string-streams help here.
Hmm - maybe you should start to think in terms of pathnames instead?
That will absolutely not make your code very compact to begin with,
but it might be more appropriate. Maybe you should really use
something like:
(defun add-file-type (basename type)
(merge-pathnames (pathname basename) (make-pathname :type type)))
instead of concatenate?
--
(espen)
If you're doing stuff with pathnames, then you should use pathnames,
not strings!
(defun typify-pathname (pathname type)
(make-pathname :type type :defaults pathname))
--tim
Then your next exercise would be to investigate pathnames and their
manipulation functions. Sorry about the string-streams detour.
> ... you're obviously not concerned with efficiency. That, or you have
> yet to discover WITH-OUTPUT-TO-STRING.
It has been our experience that the overhead to setup a string stream
for output can be quite high, at least in some implementations. It
isn't clear that using such a form will be more efficient than doing
string concatentation.
The string output formalism is convenient, however, if you already have
print functions that do what you want, or if the parts of the code that
add parts to the final string are widely scattered, with a lot of
processing or decision making in between.
--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu
Please report this is as a performance-related deficiency to the vendor.
Even more, /please/ do not discourage people from using features just
because some vendors have not yet given priority to performance. Doing
so causes the language we can depend on to shrink as vendors ignore the
parts of the standard they do not "like" and think people should not use.
> t...@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
>
> > ... you're obviously not concerned with efficiency. That, or you have
> > yet to discover WITH-OUTPUT-TO-STRING.
>
> It has been our experience that the overhead to setup a string stream
> for output can be quite high, at least in some implementations. It
> isn't clear that using such a form will be more efficient than doing
> string concatentation.
Hmm, I just checked with CMUCL, OpenMCL, and CLISP. On the latter
two, using string streams is clearly faster. CMUCL is slower, but, as
Erik noted, I consider that to be a bug (now that I noticed). I would
argue that it *should* be more efficient, though, since you're giving
the compiler more information about what you're up to.
> The string output formalism is convenient, however, if you already have
> print functions that do what you want, or if the parts of the code that
> add parts to the final string are widely scattered, with a lot of
> processing or decision making in between.
It's definately an interface that encourages doing things the right
way, so even on CMUCL, I would reccommend using it unless you've
actually determined string-streams to be the source of a performance
problem.
(defmacro abbreviate (short long)
`(defmacro ,short (&rest args)
`(,',long ,@args)))
which is used to, as the name suggests, abbreviate long named
functions and macros such as:
(abbreviate mvbind multiple-value-bind)
I find MVBIND far easier to use (except in indenting, but I use
editor:setup-indent, so even that problem is solved) than
MULTIPLE-VALUE-BIND
Thanks,
Vijay L
Vijay> t...@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) wrote in message news:<xcvd6p7...@apocalypse.OCF.Berkeley.EDU>...
>> Using abbreviations in global names is generally considered a bad
>> thing. Notice how few CL functions use them ... and those are only
>> the old ones, before the lesson was learned.
>>
Vijay> I take it that you're not very in with Paul Graham's macro: abbreviate
Vijay> (defmacro abbreviate (short long)
Vijay> `(defmacro ,short (&rest args)
Vijay> `(,',long ,@args)))
Vijay> which is used to, as the name suggests, abbreviate long named
Vijay> functions and macros such as:
Vijay> (abbreviate mvbind multiple-value-bind)
Vijay> I find MVBIND far easier to use (except in indenting, but I use
Vijay> editor:setup-indent, so even that problem is solved) than
Vijay> MULTIPLE-VALUE-BIND
If your problem is that you don't like to type long names,
why not use the abbreviation facility that is built into your editor?
For example, in Emacs, you can make the string "mvb" automatically
expand into "multiple-value-bind". You don't have to type the long
string, but also nobody who comes along looking at your code later on
has to figure out what your random abbreviation means.
Emacs can also expand m-v-b into multiple-value-bind if you use partial
completion mode. Typing less is among the best reasons to use Emacs, but
people who remain in typewriter age will likely not understand how much
redundancy there is in what we type and how few words we actually use.
"What you see is what you get" to many imply "what you type is what you
see", but this is a fantastically limiting mode of using your computer.
Why even have to program something using the abbreviation
facility of the editor? Why not use what's _already_ _available_?
I don't know how widely known this is. If, using the ELI
(emacs-lisp-interface available from Franz), and start at the
prompt (cursor represented by an underscore):
CL-USER(1): _
and then type (m-v-b:
CL-USER(1): (m-v-b_
followed by C-c TAB, I get in the particular lisp I'm using, a
completions buffer giving me two possibilities:
compiler::make-varrec-boa and multiple-value-bind, with the
common-lisp buffer remaining the same:
CL-USER(1): (m-v-b_
If I then type an i:
CL-USER(1): (m-v-bi_
and the C-c TAB, I then get the expansion:
CL-USER(1): (multiple-value-bind_
Actually, using a good editor interface which supports abbreviations
is no different than using a good editor interface to support parens:
it allows the developer to not have to resort to using programming
crutches, either in the program itself or in the editor.
--
Duane Rettig du...@franz.com Franz Inc. http://www.franz.com/
555 12th St., Suite 1450 http://www.555citycenter.com/
Oakland, Ca. 94607 Phone: (510) 452-2000; Fax: (510) 452-0182
> I don't know how widely known this is. If, using the ELI
> (emacs-lisp-interface available from Franz), and start at the
> prompt (cursor represented by an underscore):
>
> CL-USER(1): _
>
> and then type (m-v-b:
>
> CL-USER(1): (m-v-b_
>
> followed by C-c TAB, I get in the particular lisp I'm using, a
> completions buffer giving me two possibilities:
> compiler::make-varrec-boa and multiple-value-bind, with the
> common-lisp buffer remaining the same:
>
> CL-USER(1): (m-v-b_
>
> If I then type an i:
>
> CL-USER(1): (m-v-bi_
>
> and the C-c TAB, I then get the expansion:
>
> CL-USER(1): (multiple-value-bind_
...but the *Completions* buffer is still there. The first thing I do
when a new version of eli (or ilisp, for that matter) comes out is
patch it so that *Completions* disappear on the first keystroke. I
admit that this has drawbacks, too, but I can live with them happily
in return for not having to type C-x 1 all the time. I use symbol
completion too often to endure that. For the same reason (less
typing) I use Alt-TAB instead of C-c TAB, which would probably drive
people with Windows-inspired window managers crazy.
Andras
> ...but the *Completions* buffer is still there. The first thing I do
> when a new version of eli (or ilisp, for that matter) comes out is
> patch it so that *Completions* disappear on the first keystroke. I
> admit that this has drawbacks, too, but I can live with them happily
> in return for not having to type C-x 1 all the time. I use symbol
> completion too often to endure that. For the same reason (less
> typing) I use Alt-TAB instead of C-c TAB, which would probably drive
> people with Windows-inspired window managers crazy.
In my window manager, the Alt-Tab cycles through windows (most
recently used first mode). And for completions I use Meta-Tab :) And,
the Alt key is the one with the fancy winblows logo on it (happily
dedicated to all things window management related, like maximizing
window horizontally or vertically only, or both if there's really a
need for that; resizing and moving with a mouse click anywhere on the
window, switching workspaces (so I don't have to minimize/maximize the
windows all the time), etc.) Not to metion I don't have no taskbars or
similar things.
Using MS Windblows hurts after this.
--
Janis Dzerins
If million people say a stupid thing, it's still a stupid thing.
> Duane Rettig <du...@franz.com> writes:
>
> > I don't know how widely known this is. If, using the ELI
> > (emacs-lisp-interface available from Franz), and start at the
> > prompt (cursor represented by an underscore):
> >
> > CL-USER(1): _
> >
> > and then type (m-v-b:
> >
> > CL-USER(1): (m-v-b_
> >
> > followed by C-c TAB, I get in the particular lisp I'm using, a
> > completions buffer giving me two possibilities:
> > compiler::make-varrec-boa and multiple-value-bind, with the
> > common-lisp buffer remaining the same:
> >
> > CL-USER(1): (m-v-b_
> >
> > If I then type an i:
> >
> > CL-USER(1): (m-v-bi_
> >
> > and the C-c TAB, I then get the expansion:
> >
> > CL-USER(1): (multiple-value-bind_
>
> ...but the *Completions* buffer is still there. The first thing I do
> when a new version of eli (or ilisp, for that matter) comes out is
> patch it so that *Completions* disappear on the first keystroke.
This sounds like a reasonable enhancement. Have you submitted such a
change to the respective vendors for consioderation? If the developers
who support the implementations decide that your patch is worthwhile and
put it into their interfaces, then you wouldn't have to patch each new
version that comes out.
For enhancements to the ELI, send change suggestions to bu...@franz.com.
> I admit that this has drawbacks, too,
Perhaps then such behavior could be under control of a variable.
> but I can live with them happily
> in return for not having to type C-x 1 all the time. I use symbol
> completion too often to endure that. For the same reason (less
> typing) I use Alt-TAB instead of C-c TAB, which would probably drive
> people with Windows-inspired window managers crazy.
--
You and rif might benefit from pondering over Alan Perlis' epigram #34.
<shameless (but hopefully informative) plug>
For any Vim'ers out there, my VILisp package will allow Vim to do the same
thing, using Ctrl-N. See http://vim.sourceforge.net/script.php?script_id=221.
It doesn't know how to expand m-v-bi, though.
</shameless plug>
-- Larry
No, my problem is _not_ with typing long names, (I use LispWorks 4.1
which has the command bind-string-to-key, so no problems with typing),
rather, I have trouble indenting my programs and keeping the line
length <= 72 (as specified in Barry Margolin's ALU Lisp Programming
Style).
Anyways, thanks for the tips for the commands on the /real/ editor.
Thanks,
Vijay L
P.S. I call emacs the /real/ editor only because the LispWorks editor
interface provides only some of the features of emacs and no other
reason.
> P.S. I call emacs the /real/ editor only because the LispWorks
> editor interface provides only some of the features of emacs and no
> other reason.
Well, it's programmable, too. I was missing only one thing and added
it myself, now I am perfectly happy with LW's editor; at least for
writing Lisp.
Regards,
--
Nils Gösche
"Don't ask for whom the <CTRL-G> tolls."
PGP key ID 0x0655CFA0
I completely agree, as far as programming in Lisp goes: I love it.
Thanks,
Vijay L