WITH symbol conflicts between ITERATE and FSET packages
Problem
I was happy to see the new support for Iterate in Fset2. One of the feature issue comments mentions that there should be no conflict in practice with the WITH symbol between Iterate and Fset2, but that's not what I'm seeing.
Even when using the guidance around shadowing imports in the comment above, when I evaluate e.g.:
(iter
(for x below 4)
(collect (fset:with (fset:empty-map) :key :value)))
I get this error:
Iterate, in (WITH (EMPTY-MAP) KEY VALUE):
Unknown keyword KEY
The top of the backtrace looks like this (with frames 2 and 3 expanded):
0: (ITERATE::CLAUSE-ERROR "Unknown keyword ~a" :ID)
1: (ITERATE::ARG-CHECK (WITH (FSET:EMPTY-MAP) :ID :WHATEVER) #S(ITERATE::CLAUSE-INFO :FUNCTION ITERATE::CLAUSE-WITH-19 :KEYWORDS (WITH &OPTIONAL :=) :REQ-KEYWORDS (WITH) :DOC-STRING "Bind a variable" :GE..
2: (ITERATE::PROCESS-CLAUSE (WITH (FSET:EMPTY-MAP) :ID :WHATEVER))
Locals:
CLAUSE = (WITH (FSET:EMPTY-MAP) :ID :WHATEVER)
3: (ITERATE::WALK-SPECIAL-FORM (FSET:WITH (FSET:EMPTY-MAP) :ID :WHATEVER))
Locals:
FORM = (FSET:WITH (FSET:EMPTY-MAP) :ID :WHATEVER)
4: (ITERATE::WALK-EXPR (FSET:WITH (FSET:EMPTY-MAP) :ID :WHATEVER))
5: (ITERATE::RETURN-COLLECTION-CODE :VARIABLE NIL :EXPRESSION (FSET:WITH (FSET:EMPTY-MAP) :ID :WHATEVER) :START-OPERATION CONS :END-OPERATION (SUBST (ITERATE::VAR . #1=(ITERATE::EXPR)) (LIST . #1#)) :ONE..
--snip--
In the WALK-SPECIAL-FORM frame, the FORM variable contains the symbol FSET:WITH, as you'd expect, but inside that frame, the PROCESS-CLAUSE's CLAUSE variable now contains symbol ITERATE:WITH (rewritten here I believe), which perhaps is confusing the Iterate code walker. (To be clear: I haven't dived into the Iterate code, and I don't understand that magic at all.)
Repro
Context info for issue:
CL-USER> (list (lisp-implementation-type) (lisp-implementation-version))
("SBCL" "2.5.10")
;; Iterate 1.5.2 (i.e. current Quicklisp version)
CL-USER> (progn (asdf:load-system :iterate) (asdf:component-version (asdf:find-system :iterate)))
"1.5.2"
;; Fset2.0.0
CL-USER> (progn (asdf:load-system :fset/iterate) (asdf:component-version (asdf:find-system :fset)))
"2.0.0"
CL-USER> (use-package :fset/iterate)
T
CL-USER> (shadowing-import :unioning 'fset/iterate) ; get around UNIONING symbol conflict
T
CL-USER> (use-package :iterate)
T
;; Fset works fine outside of Iterate COLLECT context
CL-USER> (fset:with (fset:empty-map) :key :value)
#{| (:KEY :VALUE) |}/NIL
CL-USER> (iter (for x below 4) (collect (fset:with (fset:empty-map) :key :value)))
<Triggers error reported above>
;; Same thing using an FSet collector clause:
CL-USER> (iter (for x below 4) (collect-seq (fset:with (fset:empty-map) :key :value)))
<Triggers error reported above>
;; Any FSet macro that expands to include a WITH also causes the problem:
CL-USER> (iter (for x below 4) (collect (fset:map (:key :value))))
<Triggers same error reported above>
Workaround
I seem to be able to get around this by just doing an end-run around (either) WITH symbol, gross as this is:
CL-USER> (setf (symbol-function 'fwith) (symbol-function 'fset:with))
#<STANDARD-GENERIC-FUNCTION FSET:WITH (32)>
CL-USER> (iter (for x below 4) (collect (fwith (fset:empty-map) :key x)))
(#{| (:KEY 0) |}/NIL #{| (:KEY 1) |}/NIL #{| (:KEY 2) |}/NIL #{| (:KEY 3) |}/NIL)
Please let me know if I'm doing something incorrectly here. Thanks! (Maybe I'll have a hack at fixing this, but I can't promise anything.)