[plt-scheme] naming convention for structure constructor vs. wrapper?
On Jul 2, 2004, at 8:13 AM, Michael Sperber wrote:
> For list-related administrative tasks:
> http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
>>>>>> "Matthias" == Matthias Felleisen <matthias at ccs.neu.edu> writes:
>
> Matthias> One of my students has just had this need to use structs as
> Matthias> procedures. Correct me if I am wrong but srfi-9 wouldn't
> Matthias> support this.
>
> What do you mean "need"? A tremor starts in the little toes, sweat
> breaks out, and incomprehensible moans escape if the structs don't
> behave like procedures? :-)
Well, I may not be the student that Matthias is referring to here, but
since it is somewhat likely (2:1 odds) that whomever he is referring to
is using a macro I wrote to define these structures (because for all
its power, I will admit that MAKE-STRUCT-TYPE has a really obtuse
interface), I will describe my own need, and how I used
structures-as-procedures to rid myself of those nasty tremors and
sweats (I rather liked the moans though).
Off the top of my head, I have used structures-as-procedures in two
interesting ways.
-----
One was to define a purely functional table object that had no explicit
lookup operation; instead, when it was used as a procedure, it did a
lookup. You had to use other functions to extend the mapping.
This was mostly a syntactic convenience. There are ways to implement
tables that do not act like structures, but then you have explicit
lookup calls, which is a bear when you just want to write (MAP TABLE
KEYS).
There are also ways to implement procedures that act like tables, but
then you have to choose between linear lookup times (with the naive
extension of just wrapping another lambda around the original table
with the new key), or some sort of weird dispatch based on the number
of arguments to decide whether you are doing a lookup or exposing the
mapping. I never bothered to implement the latter, so I can't say for
sure whether its as ugly as I imagined it to be.
-----
The other was to define a special kind of partial function that
operates on a (recursively defined) algebraic datatype, but where you
can extend the partial function (in a purely functional manner) to
handle new variants in the datatype's algebra. Remember, this is a
recursive datatype; that means that you want any recursive calls in the
original function definition to call the *extended* version in the
extension.
A quick example to illustrate what I mean here:
> (define-extensible (foo num) (add1 num))
> (define-extension (foo* foo) [(num-tree) (list? x) (map foo*
num-tree)])
> (foo 3)
4
> (foo* '(3 2))
(4 3)
> (foo* '((3 2) 1))
((4 3) 2)
The above is a silly example; but hopefully you can imagine more
complex ADTs where you do want to just write the extensions
incrementally.
One could implement this functionality by writing your code as if you
were going to use the Y combinator to do the recursion, and then wait
to actually use Y until after you've incorporated all of the extensions
of interest. But that means that you need to juggle two kinds of
functions: the ones before Y's been applied, and the ones after Y's
been applied. Yuck.
I chose instead to approach it from an OO hackers point of view, where
you explicitly pass a this argument around so that you can recur on it.
Of course, I didn't want to have to use an OO syntax like (SEND proc .
args), so I found myself using structs-as-procedures to implement it.
-----
Perhaps conflating these uses with the core functionality of structures
is misguided
But the idea of being to associate data with a procedure object (other
than just the computation it provides) seems quite solid to me. And in
that sense, structs seem like an obvious choice, since they're all
about associating distinct pieces of information with each other. But
if you have an alternate syntax/semantics in mind to get this sort of
functionality, I'd love to hear your thoughts on it.
-Felix