Where looking for a generalized set! led me
Objections I read about SRFI-17
It "associates properties with Scheme symbols"
- It wants to associate properties with Scheme symbols. This is considered not in the spirit of Scheme
- In SRFI-17, setters pertain to symbols rather than procedures. That can cause problems when a symbol is rebound.
But that turns out not to be the case. It takes some careful reading to discover it, and reading the reference implementation helps. SRFI-17 associates setters to procs, not to symbols.
That bears repeating: What it associates a setter to is really a proc that you can pass to map etc. It is as if every proc becomes a double-proc of getter-and-setter form..
Some have proposed that set! should only apply to a symbol; that a generalized set should have some other name. I don't find the argument convincing and I don't agree. ISTM that when set! has a symbol as its first argument, that's a natural case of the generalized set!. So I prefer keeping the SRFI-17 syntax:
;;More general set! : (set! (proc args) value) ;;Fully general set! : (set! form value) ;;Set! as we know it: : (set! var-name value)
So I think SRFI-17 is just about right.
Andy Gaynor's proposal
I also looked at Andy Gaynor's 2000 proposal, http://srfi.schemers.org/srfi-17/mail-archive/msg00077.html
But IMO it has some drawbacks of its own:
- I don't like the multiple arguments facility. `set!' shouldn't take multiple arguments and figure out what to do with them.
In some ways it does too much. I'd prefer no `define-setter'. I'd
rather define getter and setter together. If a pre-existing
lambda's setter is to be defined, it would seem better to use
SRFI-17's proposal of:
(set! (setter x) proc).
- I'd also prefer no support for directly calling the setter. It can be done but shouldn't be part of the implementation. Setters are all about using a parallel expression for destructuring what is to be set. Using a setter explicitly is just calling a function. Why support that specially?
What else might have a setter?
One interesting candidate for having a setter is `assoc'. There are different interpretations:
- If the associated item is not found, add it, otherwise mutate it.
- If the associated item is not found, error, otherwise mutate it. So the set of keys is immutable.
- If the associated item is not found, add it, otherwise error. So the existing mappings are immutable.
If we're going to allow these double-lambdas to have two fields, why not more? Some other possibilities:
- "pusher" and "popper", useful when the underlying type is a container.
- docstring, a string or a function which yields documentation.
- "accessor-doc", a function that describes the accessor, suitable for combining to tell where a thing is located.
"matcher" - allowing constructor functions to have counterparts for
- It would be nice to can use this for formals in arglists.
"type" of the proc
- Min/max arity
- Argument types
- Promises about it
- Other type information
"merge", which tries to advantageously merge a given call to the
function with other calls immediately before or after it.
- How: It is passed this call and preceding calls, returns a merge or #f.
- A smart merge-manager may know what functions it can hop over.
- Specializations. List of the available specializations.
- Hidden read/clobbered arguments.
- compiler-macro as in Common Lisp
- Profiling data
- "merge", which tries to advantageously merge a given call to the function with other calls immediately before or after it.
Lambda as an extensible type
So this extended lambda would be an object type. Since the type will be so extensible, we'll want a base type that provides this minimally and can be extended. So that base type must be recognized by the eval loop as applyable.