3 ms·
Apologies for being slightly unclear. For both getting function composition and avoiding unnecessary intermediate allocations, the naive approach to using the
by dapperdrake 3y ago
Apologies for being slightly unclear.
For both getting function composition and avoiding unnecessary intermediate
allocations, the naive approach to using the SERIES package is insufficient.
And the error messages it returns along the way are unhelpful.
Evaluating (defpackage foo (:use :cl :series)) fails to import
(series::defun ...) and (series::let ...) and (series::let* ...).
So, when you think you are following the rules of the paper, you are
invisibly not following the rules of the paper and get the appropriate
warnings about pipelining being impossible. That seems somewhat confusing.
After reading the source code, it turns out the answer is calling
(series::install :shadow T :macro T :implicit-map nil). How is
(series::install ...) supposed to be discoverable with
(describe (find-package :series)) in SBCL if it is an internal
symbol of package SERIES (?) Usability here is somewhat less than discoverable.
Listing all exported package symbols of SERIES obviously also fails here.
Furthermore, the source code and naming in "s-code.lisp" suggest that
(series::process-top ...) may be useful for expanding series expressions
to their pipelined (read optimized/streaming/lazy) implementations.
This is desirable for passing the optimized version on to PARENSCRIPT
or other compilers. Here is the catch: It fails when the series expression
is supposed to return multiple values. One of the points of using SERIES,
is that Waters and his fellow researchers already took care of handling
multiple return values. (If the lisp implementation is smart enough, this
seems to mean that these values are kept in registers during processing.)
After some tinkering, there is a solution that also handles multiple
return values:
(defun series-expand (series-expression)
"(series::process-top ...) has problems with multiple return values."
(let (series::*renames*
series::*env*)
(series::codify
(series::mergify
(series::graphify
series-expression)))))
Will submit pull requests once I am comfortable enough with the source code.
Yes, the SERIES papers Waters(1989a,b) bemoan the lack of deep integration
with Common Lisp compilers. And yes, they could have been resolved by
making SERIES part of ANSI Common Lisp like LOOP was. They could
theoretically also have been resolved by having explicit compiler and
environment interfaces in ANSI Common Lisp. That is not the world we
seem to live in today. Nevertheless, package SERIES solved all of the
hard technical problems. When people know about the documentation
failings, then SERIES is a powerful hammer for combining streaming/lazy-evaluation with function composition as well as other compilers like
PARENSCRIPT.
- kazinator 3y agoI think, one issue is that Series had been hacked on since that paper, which had not been updated. Anyway, I guess series::let is an unexported symbol? I.e. not series:let? There is a good reason for that. If series:let were exported, then you would get a clash condition by doing (:use :cl :series). The CL package system detects and flags ambiguous situations in which different symbols would become visible under the same name. You would need to a shadowing import for all the clashing symbols. It's probably a bad idea for any package to export symbols that have the same names as CL symbols. Other people say that using :use (other than for the CL package) is a bad idea. Either way, if you have clashing symbols, whether exported or not, you're going to be importing them individually if you also use CL, which is often the case.