News for hackers. Stuff that matters.
Re:Bun v0.8.0 by dapperdrake on Thursday August 24, 2023 @11:34AM (#37250055)
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.

Re:Bun v0.8.0 by kazinator on Thursday August 24, 2023 @11:57AM (#37250410)
I 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.