From: Pascal Costanza on
Ron Garret wrote:
> In article <7o00puF3nuc41U1(a)mid.individual.net>,
> Pascal Costanza <pc(a)p-cos.net> wrote:
>
>> Ron Garret wrote:
>>> In article <7nvteeF3mopq6U1(a)mid.individual.net>,
>>> Pascal Costanza <pc(a)p-cos.net> wrote:
>>>
>>>> Ron Garret wrote:
>>>>> In article <7nvrpuF3nupc4U1(a)mid.individual.net>,
>>>>> Pascal Costanza <pc(a)p-cos.net> wrote:
>>>>>
>>>>>> Ron Garret wrote:
>>>>>>> In article <7ntfj7F3m9fjiU1(a)mid.individual.net>,
>>>>>>> Pascal Costanza <pc(a)p-cos.net> wrote:
>>>>>>>
>>>>>>>> Filtered functions are an extension of generic functions, extended
>>>>>>>> with
>>>>>>>> a filtering step where the arguments received by a generic function
>>>>>>>> are
>>>>>>>> mapped to other values based on user-defined mapping functions. Those
>>>>>>>> filtered values are then used to perform the actual selection and
>>>>>>>> execution of applicable methods. Nevertheless, the methods that are
>>>>>>>> eventually executed see the original objects as received by the
>>>>>>>> generic
>>>>>>>> function, and not the filtered ones.
>>>>>>> I like this concept, but is there a reason you designed the API the way
>>>>>>> you did instead of simply providing a facility for subclassing built-in
>>>>>>> classes? In other words, why not simply do:
>>>>>>>
>>>>>>> (def-subclass positive-integer integer 'plusp)
>>>>>>>
>>>>>>> (defmethod factorial ((n positive-integer)) ...)
>>>>>>>
>>>>>>> That would seem to me to provide the same functionality, and would make
>>>>>>> code using this feature easier to write and debug.
>>>>>> Maybe this would work for this particular example (but factorial is
>>>>>> really not that interesting now, is it? ;).
>>>>>>
>>>>>> Just check the other examples as well, I don't think you could solve
>>>>>> them that easily.
>>>>> Obviously factorial is not the definitive test case, but I'm pretty sure
>>>>> that the two APIs are formally equivalent. Is there a particular
>>>>> example that you think could not be easily rendered in terms of
>>>>> def-subclass?
>>>> Yes, the other two examples in the paper. Especially the interpreter,
>>>> but also the state example. I actually want to experiment with state
>>>> being dynamically scoped such that you can have behavior depend on
>>>> particular special variables. In conjunction with special slots in
>>>> ContextL this means that it should be possible to have context-dependent
>>>> object-specific behavior - something which is currently not possible
>>>> with ContextL.
>>>>
>>>> Maybe you can express such things with class hierarchies, but I don't
>>>> think that's convenient.
>>> Well, here's how I'd do it:
>>>
>>> (defun make-filter (key-function expected-result)
>>> (lambda (thing) (eq (funcall key-function thing) expected-result)))
>>>
>>> (def-subclass regular-stack stack (make-filter 'stack-state 'normal))
>>>
>>> (def-subclass full-stack stack (make-filter 'stack-state 'full))
>>>
>>> (def-subclass empty-stack stack (make-filter 'stack-state 'empty))
>>>
>>> (defmethod stack-whatever ((stack regular-stack) ...) ...)
>>> (defmethod stack-whatever ((stack empty-stack) ...) ...)
>>> (defmethod stack-whatever ((stack full-stack) ...) ...)
>>>
>>> And the EVAL example:
>>>
>>> (defun make-form-type-checker (spec)
>>> (lambda (form) (eq (car form) spec)))
>>>
>>> (def-subclass quote-form cons (make-filter 'car 'quote))
>>> (def-subclass lambda-form cons (make-filter 'car 'lambda))
>>> etc...
>>>
>>> (defmethod eval ((form quote-form)) form)
>>> (defmethod eval ((form lambda-form)) (make-closure ...))
>>>
>>> Seems pretty convenient to me.
>> Can you provide a definition for def-subclass?
>
> Probably, though I might have to shadow defmethod and defgeneric. I do
> not posses your level of MOP guruness. But first things first: would
> you agree that def-subclass can do everything (or at least all the
> worthwhile things) that filtered functions can do and that the interface
> is cleaner?

It may look cleaner (not sure about that), but I don't know how this
should work...

You seem to want to have a global space for defining potential filters,
and then somehow infer from the defined methods which of them are used
for a particular generic function. But that leaves the question open
which one is the most specific one if several of them apply.

Consider:

(def-subclass prime-number integer (make-filter 'primep t))
(def-subclass even-number integer (make-filter 'evenp t))

(defmethod foo ((n prime-number)) (do-this))
(defmethod foo ((n even-number)) (do-that))

(foo 2) => should this perform do-this or do-that? Neither prime-number
is a subclass/subset of even-number, nor the other way around, so it's
unclear what the method specificity should be.

Now with filtered functions:

(define-filtered-function foo (n)
(:filters (:prime #'primep)
(:even #'evenp)))

(defmethod foo :filter :prime ((n (eql t))
(do-this))

(defmethod foo :filter :even ((n (eql t)))
(do-that))

(foo) => this will perform do-that, because the filter :even comes after
the filter :prime in the define-filtered-function form.

So how do you want to specify that when using def-subclass?


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret on
In article <7o0365F3m83ioU1(a)mid.individual.net>,
Pascal Costanza <pc(a)p-cos.net> wrote:

> Ron Garret wrote:
> > In article <7ntfj7F3m9fjiU1(a)mid.individual.net>,
> > Pascal Costanza <pc(a)p-cos.net> wrote:
> >
> >> Filtered functions are an extension of generic functions, extended with
> >> a filtering step where the arguments received by a generic function are
> >> mapped to other values based on user-defined mapping functions. Those
> >> filtered values are then used to perform the actual selection and
> >> execution of applicable methods. Nevertheless, the methods that are
> >> eventually executed see the original objects as received by the generic
> >> function, and not the filtered ones.
> >
> > I like this concept, but is there a reason you designed the API the way
> > you did instead of simply providing a facility for subclassing built-in
> > classes? In other words, why not simply do:
> >
> > (def-subclass positive-integer integer 'plusp)
> >
> > (defmethod factorial ((n positive-integer)) ...)
> >
> > That would seem to me to provide the same functionality, and would make
> > code using this feature easier to write and debug.
>
> How does the factorial function know which def-subclass definitions to
> take into account?

The same way it knows which methods to take into account. (Maybe I
don't understand the question.)

> Should it try all of them? A subset? Based on what criteria?

I'm not sure what you mean by "try" in this context. It should proceed
in the same way as any method application, by assembling a set of
applicable methods and combining them according to the appropriate
method combination. Implementing this efficiently could be tricky, but
I don't see why this should be at all problematic on a conceptual level.

> What does it do with the ones where the predicate fails (by
> signaling an error)?

Of course not. Why would you think that would even be a reasonable
possibility?

> If several of the def-subclass forms apply, which one is selected? Are
> they all selected? In what order? What is the most specific one, what is
> the last specific one, and so on?

I presume you mean something like this:

(def-subclass positive-integer 'integer 'plusp)
(def-subclass odd-integer 'integer 'oddp)

(defmethod m1 ((x positive-integer)) 'positive)
(defmethod m1 ((x odd-integer)) 'odd)

(m1 3) --> ???

This situation is completely analogous to:

(defclass c1 () ())
(defclass c2 () ())
(defclass c3 (c1 c2) ())

(defmethod m1 ((x c1)) 1)
(defmethod m1 ((c c2)) 2)
(m1 (make-instance 'c3)) --> ???

In the latter case the ambiguity is resolved because the superclasses of
C3 are listed in order. A similar solution could be applied to
sub-classes, i.e. a total order could be imposed on all sub-classes of a
given class. Exactly how this would be done is TBD, but surely you
don't dispute that it could be done this way?


> These are the typical issues you have to solve when designing
> predicate-dispatch-style systems, and they are not trivial to solve
> (basically because of the halting problem).

I don't see why. Certainly there are designs that would run afoul of
the halting problem, but I don't see that this is necessarily so. So
all you have to do is pick a design that doesn't, like imposing a total
order on all the subclasses of a given class, and then making the rest
of the design analogous to what already exists in CLOS.

> Filtered functions solve this by defining the acceptable filters along
> with the filtered function definition, and by defining an order among
> filters along the way that can be chosen per filtered function.
>
> The idea to specify an order between custom filters (specializers) was
> first described by Jim Newton, and is described in more detail in a
> paper by Jim Newton and Christophe Rhodes. The difference between their
> approach and ours is that in their approach, the order is defined at the
> meta-level (as part of the MOP), whereas here it is defined at the
> base-level (as part of the define-filtered-function form). I think the
> latter is more convenient, since the orders tend to be ad hoc anyway, as
> far as I can tell.
>
> Having per-function orders seems to have been adopted by now in Clojure
> as well.

I have still not had a chance to actually read your paper (and probably
won't until tomorrow at the earliest) so I may well be missing something
really important. But based on your responses so far I can't imagine
what that might be.

rg
From: Kenneth Tilton on
Raffael Cavallaro wrote:
> On 2009-12-05 17:52:27 -0500, Kenneth Tilton <kentilton(a)gmail.com> said:
>
>> Oh, good! You don't know what "sour grapes" means!
>
> I know perfectly, you're just having difficulty identifying the
> metaphorical grapes. They are, to spell it out in painful detail once
> again, writing a *publication quality* *well documented* *well received*
> extension to CLOS. Since you haven't done this, you're criticizing
> someone who *has* as performing "stupid CLOS tricks." This critique
> ("stupid CLOS tricks") of something you wish you had done (a
> *publication quality* *well documented* *well received* extension to
> CLOS) is crying "sour grapes."

Sour grapes is about pooh-poohing something I cannot have. I can have
filtered functions*. QED.

Don't feel bad, your english is way better than my spanish.

* I would not blame Pascal for modifying the license to exclude me.

>> Meanwhile, I provided a thumbs-down analysis on the whole idea of GFs
>> to justify my assessment of an enhancement thereto, to which you
>> responded with irrelevant guesswork as to my motivation. I guess if
>> you have no defense of GFs to offer, that was a smart move.
>
> The only justification for any feature in an extensible language like
> lisp is whether or not it allows you to more easily shape the language
> to the way you think.

Oy, vey. The proof is in the pudding, aka the application, not some
abstract guess about "shaping". I have developed hundreds of application
KLOC with Cells during which (to my surprise) I honestly lost interest
in GFs as anything more than incrementally nice.

Sorry to keep dragging the discussion back to the value of GFs, I know
you want to make me feel bad about some unrelated software.

kt
From: Ron Garret on
In article <rNOSPAMon-D137E5.16071705122009(a)news.albasani.net>,
Ron Garret <rNOSPAMon(a)flownet.com> wrote:

> > What does it do with the ones where the predicate fails (by
> > signaling an error)?
>
> Of course not. Why would you think that would even be a reasonable
> possibility?

Oops, I just realized I parsed that question completely wrong.

> I have still not had a chance to actually read your paper (and probably
> won't until tomorrow at the earliest) so I may well be missing something
> really important. But based on your responses so far I can't imagine
> what that might be.

I've now had a chance to skim the paper, and so I think I now understand
the motivation behind doing it the way you did.

FWIW, I still think I would personally prefer a dispatch system which
leaves it up to me (the programmer) to insure that the predicates I use
halt, don't raise errors, and have some kind of total ordering defined
on them. But I now see how a reasonable person could disagree, and how
filtered functions solve certain problems that dispatch has to either
punt on or fob off onto the programmer.

rg
From: Ron Garret on
In article <7o0asgF3l7u67U1(a)mid.individual.net>,
Pascal Costanza <pc(a)p-cos.net> wrote:

> Ron Garret wrote:
> > In article <7o00puF3nuc41U1(a)mid.individual.net>,
> > Pascal Costanza <pc(a)p-cos.net> wrote:
> >
> >> Ron Garret wrote:
> >>> In article <7nvteeF3mopq6U1(a)mid.individual.net>,
> >>> Pascal Costanza <pc(a)p-cos.net> wrote:
> >>>
> >>>> Ron Garret wrote:
> >>>>> In article <7nvrpuF3nupc4U1(a)mid.individual.net>,
> >>>>> Pascal Costanza <pc(a)p-cos.net> wrote:
> >>>>>
> >>>>>> Ron Garret wrote:
> >>>>>>> In article <7ntfj7F3m9fjiU1(a)mid.individual.net>,
> >>>>>>> Pascal Costanza <pc(a)p-cos.net> wrote:
> >>>>>>>
> >>>>>>>> Filtered functions are an extension of generic functions, extended
> >>>>>>>> with
> >>>>>>>> a filtering step where the arguments received by a generic function
> >>>>>>>> are
> >>>>>>>> mapped to other values based on user-defined mapping functions.
> >>>>>>>> Those
> >>>>>>>> filtered values are then used to perform the actual selection and
> >>>>>>>> execution of applicable methods. Nevertheless, the methods that are
> >>>>>>>> eventually executed see the original objects as received by the
> >>>>>>>> generic
> >>>>>>>> function, and not the filtered ones.
> >>>>>>> I like this concept, but is there a reason you designed the API the
> >>>>>>> way
> >>>>>>> you did instead of simply providing a facility for subclassing
> >>>>>>> built-in
> >>>>>>> classes? In other words, why not simply do:
> >>>>>>>
> >>>>>>> (def-subclass positive-integer integer 'plusp)
> >>>>>>>
> >>>>>>> (defmethod factorial ((n positive-integer)) ...)
> >>>>>>>
> >>>>>>> That would seem to me to provide the same functionality, and would
> >>>>>>> make
> >>>>>>> code using this feature easier to write and debug.
> >>>>>> Maybe this would work for this particular example (but factorial is
> >>>>>> really not that interesting now, is it? ;).
> >>>>>>
> >>>>>> Just check the other examples as well, I don't think you could solve
> >>>>>> them that easily.
> >>>>> Obviously factorial is not the definitive test case, but I'm pretty
> >>>>> sure
> >>>>> that the two APIs are formally equivalent. Is there a particular
> >>>>> example that you think could not be easily rendered in terms of
> >>>>> def-subclass?
> >>>> Yes, the other two examples in the paper. Especially the interpreter,
> >>>> but also the state example. I actually want to experiment with state
> >>>> being dynamically scoped such that you can have behavior depend on
> >>>> particular special variables. In conjunction with special slots in
> >>>> ContextL this means that it should be possible to have context-dependent
> >>>> object-specific behavior - something which is currently not possible
> >>>> with ContextL.
> >>>>
> >>>> Maybe you can express such things with class hierarchies, but I don't
> >>>> think that's convenient.
> >>> Well, here's how I'd do it:
> >>>
> >>> (defun make-filter (key-function expected-result)
> >>> (lambda (thing) (eq (funcall key-function thing) expected-result)))
> >>>
> >>> (def-subclass regular-stack stack (make-filter 'stack-state 'normal))
> >>>
> >>> (def-subclass full-stack stack (make-filter 'stack-state 'full))
> >>>
> >>> (def-subclass empty-stack stack (make-filter 'stack-state 'empty))
> >>>
> >>> (defmethod stack-whatever ((stack regular-stack) ...) ...)
> >>> (defmethod stack-whatever ((stack empty-stack) ...) ...)
> >>> (defmethod stack-whatever ((stack full-stack) ...) ...)
> >>>
> >>> And the EVAL example:
> >>>
> >>> (defun make-form-type-checker (spec)
> >>> (lambda (form) (eq (car form) spec)))
> >>>
> >>> (def-subclass quote-form cons (make-filter 'car 'quote))
> >>> (def-subclass lambda-form cons (make-filter 'car 'lambda))
> >>> etc...
> >>>
> >>> (defmethod eval ((form quote-form)) form)
> >>> (defmethod eval ((form lambda-form)) (make-closure ...))
> >>>
> >>> Seems pretty convenient to me.
> >> Can you provide a definition for def-subclass?
> >
> > Probably, though I might have to shadow defmethod and defgeneric. I do
> > not posses your level of MOP guruness. But first things first: would
> > you agree that def-subclass can do everything (or at least all the
> > worthwhile things) that filtered functions can do and that the interface
> > is cleaner?
>
> It may look cleaner (not sure about that), but I don't know how this
> should work...
>
> You seem to want to have a global space for defining potential filters,
> and then somehow infer from the defined methods which of them are used
> for a particular generic function. But that leaves the question open
> which one is the most specific one if several of them apply.
>
> Consider:
>
> (def-subclass prime-number integer (make-filter 'primep t))
> (def-subclass even-number integer (make-filter 'evenp t))
>
> (defmethod foo ((n prime-number)) (do-this))
> (defmethod foo ((n even-number)) (do-that))
>
> (foo 2) => should this perform do-this or do-that? Neither prime-number
> is a subclass/subset of even-number, nor the other way around, so it's
> unclear what the method specificity should be.
>
> Now with filtered functions:
>
> (define-filtered-function foo (n)
> (:filters (:prime #'primep)
> (:even #'evenp)))
>
> (defmethod foo :filter :prime ((n (eql t))
> (do-this))
>
> (defmethod foo :filter :even ((n (eql t)))
> (do-that))
>
> (foo) => this will perform do-that, because the filter :even comes after
> the filter :prime in the define-filtered-function form.
>
> So how do you want to specify that when using def-subclass?

In the exact same way: by providing a mechanism to specify a total
ordering on the sub-classes of a given class, just as you provide a
mechanism to specify a total ordering on filters. (Exactly what that
mechanism would be is TBD.)

rg
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Prev: [ANN] Filtered functions
Next: Filtered functions.