11 September 2010

Scheme setters

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..

Its syntax

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)

Conclusion

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:

pushnew
If the associated item is not found, add it, otherwise mutate it.
mutate-only
If the associated item is not found, error, otherwise mutate it. So the set of keys is immutable.
new-only
If the associated item is not found, add it, otherwise error. So the existing mappings are immutable.

More fields

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 pattern-matching.
    • 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
  • "evaluation-type"
    • normal
    • macro
    • built-in
  • Optimization 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

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.

No comments:

Post a Comment