Re: Emacs Lisp's "mapconcat" in Common Lisp?
- From: Vassil Nikolov <vnikolov@xxxxxxxxx>
- Date: Mon, 13 Jul 2009 23:44:57 -0400
Here is my take on implementing what Barry Margolin proposed. (As
this is, at heart, a map/reduce problem, his suggestion allows this
kind of solution without a very bad performance hit.) One reason I am
interested in this is the opportunity to generalize `mapconcat' by
being able to specify the type of the resulting sequence. So, for
example:
(map-concatenate 'list #'list '(foo bar baz) (list '-))
=> (FOO - BAR - BAZ)
(map-concatenate 'string #'string '(foo bar baz) (string '-))
=> "FOO-BAR-BAZ"
(not just theoretical physicists like symmetries).
I also wanted to keep things sequence-generic and thus limited myself
to MAP, REDUCE, & Co.
The resulting solution is---I am tempted to say "of course"---slower
than the WRITE-STRING/WITH-OUTPUT-TO-STRING solution. This is in part
the price to pay for greater generality; in part because I saved
myself the effort or the complications of some optimizations; in part
because I did not want to spend time hand-crafting specialized
solutions for specific sequence types; and in part because this kind
of programs have a greater need for an SSC to be mechanically
optimized.
On the other hand, doing it with concatenation (as opposed to an
iteration, whether by means of MAP of NIL or FORMAT's ``~{...~}''), is
more amenable to parallelization, and this is also an example
illustrating the well-known importance of associativity of operations
(such as concatenation) in this regard. (Associativity also allows
REDUCE of ``:FROM-END T'', which may have---as in this case---a
dramatic effect on performance.)
* * *
(defun map-concatenate (type f xs s)
"Concatenate into a TYPE sequence the values of F on XS, S-separated.
For example, (MAPCONCAT F XS S) <=> (MAP-CONCATENATE 'STRING F XS S).
\"Demo\" grade."
(reduce-am #'(lambda (&rest ss) (apply #'concatenate type ss))
;; the interspersing:
(rest (reduce #'(lambda (x y) (list* s x y))
(map 'list f xs)
:from-end t :initial-value '()))))
(defun reduce-am (f xs &key (limit (- call-arguments-limit 1)))
"Reduce by F the sequence XS, with each application on LIMIT elements.
\"AM\" stands for F being associative and of multiple arguments.
\"Demo\" grade."
(cond ((not (listp xs)) (reduce-am f (coerce xs 'list)) :limit limit)
((endp (rest xs)) (apply f xs))
(t (reduce-am f (reduce-am-1-list f xs limit) :limit limit))))
(defun reduce-am-1-list (f xs limit)
"Perform one pass applying F to parts of the list XS, each LIMIT elements.
Return a list of the results. Used by REDUCE-AM. \"Demo\" grade."
;; this can be made iterative fairly easily
(multiple-value-bind (value tail) (reduce-am-1 f xs limit)
(if (endp tail) (list value)
(cons value (reduce-am-1-list f tail limit)))))
(defun reduce-am-1 (f xs limit)
"Apply F to the list XS's first LIMIT elements.
Return the result and as a second value, the remaining part of XS.
Used by REDUCE-AM-1-LIST. \"Demo\" grade."
(let ((tail (nthcdr (min limit (length xs)) xs)))
(values (apply f (ldiff xs tail)) tail)))
---Vassil.
--
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
.
- References:
- Emacs Lisp's "mapconcat" in Common Lisp?
- From: Teemu Likonen
- Re: Emacs Lisp's "mapconcat" in Common Lisp?
- From: Thomas A. Russ
- Re: Emacs Lisp's "mapconcat" in Common Lisp?
- From: Teemu Likonen
- Re: Emacs Lisp's "mapconcat" in Common Lisp?
- From: Jimmy Miller
- Re: Emacs Lisp's "mapconcat" in Common Lisp?
- From: Robert Uhl
- Re: Emacs Lisp's "mapconcat" in Common Lisp?
- From: Barry Margolin
- Emacs Lisp's "mapconcat" in Common Lisp?
- Prev by Date: Re: LISP vs HASKELL vs PROLOG
- Next by Date: Re: LISP vs HASKELL vs PROLOG
- Previous by thread: Re: Emacs Lisp's "mapconcat" in Common Lisp?
- Next by thread: Re: Emacs Lisp's "mapconcat" in Common Lisp?
- Index(es):
Relevant Pages
|