From: Raffael Cavallaro on
On 2009-12-04 17:08:39 -0500, Pascal Costanza <pc(a)p-cos.net> said:

> I am very excited that I can finally annouce a public release of
> 'filtered functions'

This is excellent news! predicate dispatch portable across 6
implementations - amazing!

thanks for sharing this
--
Raffael Cavallaro

From: Pillsy on
On Dec 4, 5:08 pm, Pascal Costanza <p...(a)p-cos.net> wrote:

> I am very excited that I can finally annouce a public release of
> 'filtered functions', an extension of generic functions that Charlotte
> Herzeel, Jorge Vallejos, and myself have developed some time ago and
> that we are very excited about because it seems to be quite powerful in
> a number of very different scenarios.

This looks really impressive.

Cheers,
Pillsy
From: vanekl on
On Dec 4, 9:19 pm, Raffael Cavallaro
<raffaelcavall...(a)pas.espam.s.il.vous.plait.mac.com> wrote:
> On 2009-12-04 17:08:39 -0500, Pascal Costanza <p...(a)p-cos.net> said:
>
> > I am very excited that I can finally annouce a public release of
> > 'filtered functions'
>
> This is excellent news! predicate dispatch portable across 6
> implementations - amazing!
>
> thanks for sharing this
> --
> Raffael Cavallaro

Where did you read six? I thought his paper said it's only fully
implemented on one, SBCL.
From: Kenneth Tilton on
Pascal Costanza wrote:
> Hi,
>
> I am very excited that I can finally annouce a public release of
> 'filtered functions', an extension of generic functions that Charlotte
> Herzeel, Jorge Vallejos, and myself have developed some time ago and
> that we are very excited about because it seems to be quite powerful in
> a number of very different scenarios. It took a while to release
> filtered functions, because it is a quite non-trivial extension of
> generic functions and requires a CLOS MOP implementation that is
> compliant with the AMOP specification to quite a deep level. Therefore,
> this required some serious preparation in the form of a much improved
> Closer to MOP library, that I released today as well.
>
> You can find filtered functions at the Closer project website at
> http://common-lisp.net/project/closer/ - below you will find a general
> overview of the concept.
>
> 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.
>
> Here are some examples to illustrate the expressive power of filtered
> functions.
>
> Factorial
> =========
>
> In order to be able to use filtered functions, we need to have filter
> functions that map received arguments to values that we actually want to
> base our dispatch on. For the factorial function, we want to distinguish
> between negative and positive numbers, and the number zero. For that we
> can just use the Common Lisp function SIGNUM that returns +1 for
> positive numbers, -1 for negative numbers, and just 0 for the number 0.
> The filtered function FAC can thus be defined as follows.
>
> (define-filtered-function fac (n)
> (:filters (:sign #'signum)))
>
> DEFINE-FILTERED-FUNCTION is exactly like DEFGENERIC, except that it can
> also define one or more filters. Here, it defines a filter with the name
> :SIGN wich specifices that the function SIGNUM is to be used for filtering.
>
> We can now define methods for FAC:
>
> (defmethod fac :filter :sign ((n (eql +1)))
> (* n (fac (- n 1))))
>
> (defmethod fac :filter :sign ((n (eql 0)))
> 1)
>
> (defmethod fac :filter :sign ((n (eql -1)))
> (error "Fac not defined for negative numbers."))
>
> Here, we use the qualifiers :FILTER :SIGN in the method definitions to
> indicate that we indeed want to use the :SIGN filter for method
> selection. We then use EQL specializers to ensure that the method
> definitions are applicable for the three different cases that SIGNUM
> yields. Remember that the method bodies always see the original
> arguments, not the filtered ones, and this is why the FAC methods can do
> the correct computations.
>
> State pattern
> =============
>
> Filtered functions can be used to dispatch methods based on the state of
> an argument passed to a filtered function, which enables expressing
> State-like idioms. Assume the following simple CLOS class is defined for
> implementing a stack.
>
> (defconstant +stack-size+ 10)
>
> (defclass stack ()
> ((contents :initform (make-array +stack-size+)
> :reader stack-contents))
> (index :initform 0
> :accessor stack-index)))
>
> Instances of this class have three different states: Such a stack can
> either be empty, or full, or anywhere in between (in 'normal' state). We
> can express this as a function that recognizes the state of a stack.
>
> (defun stack-state (stack)
> (cond ((<= (stack-index stack) 0) 'empty)
> ((>= (stack-index stack) +stack-size+) 'full)
> (t 'normal)))
>
> It is now straightforward to use stack-state in a filter named :state
> for the typical stack operations.
>
> (define-filtered-function stack-push (stack value)
> (:filters (:state #'stack-state)))
>
> (define-filtered-function stack-pop (stack)
> (:filters (:state #'stack-state)))
>
> (define-filtered-function stack-emptyp (stack)
> (:filters (:state #'stack-state)))
>
> We can now group the behavior of a stack according to its different
> states. Note that for 'normal' state, we do not need to mention the use
> of any filter here, because the methods are not specialized on anything
> specific anyway. (Filtered functions always allow for 'regular' methods
> alongside the filtered methods.)
>
> ;;; Normal state
>
> (defmethod stack-push (stack value)
> (setf (aref (stack-contents stack)
> (stack-index stack))
> value)
> (incf (stack-index stack)))
>
> (defmethod stack-pop (stack)
> (decf (stack-index stack))
> (aref (stack-contents stack)
> (stack-index stack)))
>
> (defmethod stack-emptyp (stack)
> nil)
>
> ;;; Empty state
>
> (defmethod stack-pop :filter :state ((stack (eql 'empty)))
> (error "Stack is empty."))
>
> (defmethod stack-emptyp :filter :state ((stack (eql 'empty)))
> t)
>
> ;;; Full state
>
> (defmethod stack-push :filter :state ((stack (eql 'full)) value)
> (error "Stack is full."))
>
> Note that we used a derived state function here, that determines the
> state of the stack based on some of its other properties. Since filter
> functions can be any functions, we could also use the reader of a slot
> as a filter function, and thus have the behavior of a filtered function
> depend on the explicit state of an object.
>
> Filtered functions can do a lot more: As already mentioned, they can use
> more than one filter; filter functions can see all the arguments a
> generic function receives; and filters can be guarded, which means that
> methods that use a particular filter may be completely ignored if the
> arguments don't fulfil a certain predicate. You can read the paper
> "Filtered Dispatch" at http://p-cos.net/documents/filtered-dispatch.pdf
> that I co-authored with Charlotte Herzeel, Jorge Vallejos and Theo
> D'Hondt for a more thorough introduction, background information and
> semantics, and which also includes an extensible metacircular Lisp
> interpreter as an example, based on implementing EVAL as a filtered
> function.

What was wrong with COND? ie, Where is the productivity advantage of
chopping code up into methods? One starts with a step backward: the code
is now spread all over the map. The failure of OO to provide more than a
marginal boost to programming productivity exposed the absence of
emperor clothes in this case. ie, It is great fun to have different
parameters produce different results according to their type, it just
turned out not to solve any real problem with software development.
Taking that further just means even more spaghettish dispatch.

Filed under "Stupid CLOS Tricks".

kt

ps. Hoping you at least got a paper out of this. k

pps. Factorial as a use case? Plz tell me that was a joke. k

--

http://thelaughingstockatpngs.com/
http://www.facebook.com/pages/The-Laughingstock/115923141782?ref=nf
From: Slobodan Blazeski on
On Dec 4, 11:08 pm, Pascal Costanza <p...(a)p-cos.net> wrote:
> Hi,
>
> I am very excited that I can finally annouce a public release of
> 'filtered functions', an extension of generic functions that Charlotte
> Herzeel, Jorge Vallejos, and myself have developed some time ago and
> that we are very excited about because it seems to be quite powerful in
> a number of very different scenarios. It took a while to release
> filtered functions, because it is a quite non-trivial extension of
> generic functions and requires a CLOS MOP implementation that is
> compliant with the AMOP specification to quite a deep level. Therefore,
> this required some serious preparation in the form of a much improved
> Closer to MOP library, that I released today as well.
>
> You can find filtered functions at the Closer project website athttp://common-lisp.net/project/closer/- below you will find a general
> overview of the concept.
>
> 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.
>
> Here are some examples to illustrate the expressive power of filtered
> functions.
>
> Factorial
> =========
>
> In order to be able to use filtered functions, we need to have filter
> functions that map received arguments to values that we actually want to
> base our dispatch on. For the factorial function, we want to distinguish
> between negative and positive numbers, and the number zero. For that we
> can just use the Common Lisp function SIGNUM that returns +1 for
> positive numbers, -1 for negative numbers, and just 0 for the number 0.
> The filtered function FAC can thus be defined as follows.
>
> (define-filtered-function fac (n)
>    (:filters (:sign #'signum)))
>
> DEFINE-FILTERED-FUNCTION is exactly like DEFGENERIC, except that it can
> also define one or more filters. Here, it defines a filter with the name
> :SIGN wich specifices that the function SIGNUM is to be used for filtering.
>
> We can now define methods for FAC:
>
> (defmethod fac :filter :sign ((n (eql +1)))
>    (* n (fac (- n 1))))
>
> (defmethod fac :filter :sign ((n (eql 0)))
>    1)
>
> (defmethod fac :filter :sign ((n (eql -1)))
>    (error "Fac not defined for negative numbers."))
>
> Here, we use the qualifiers :FILTER :SIGN in the method definitions to
> indicate that we indeed want to use the :SIGN filter for method
> selection. We then use EQL specializers to ensure that the method
> definitions are applicable for the three different cases that SIGNUM
> yields. Remember that the method bodies always see the original
> arguments, not the filtered ones, and this is why the FAC methods can do
> the correct computations.
>
> State pattern
> =============
>
> Filtered functions can be used to dispatch methods based on the state of
> an argument passed to a filtered function, which enables expressing
> State-like idioms. Assume the following simple CLOS class is defined for
> implementing a stack.
>
> (defconstant +stack-size+ 10)
>
> (defclass stack ()
>    ((contents :initform (make-array +stack-size+)
>               :reader stack-contents))
>     (index :initform 0
>            :accessor stack-index)))
>
> Instances of this class have three different states: Such a stack can
> either be empty, or full, or anywhere in between (in 'normal' state). We
> can express this as a function that recognizes the state of a stack.
>
> (defun stack-state (stack)
>    (cond ((<= (stack-index stack) 0) 'empty)
>          ((>= (stack-index stack) +stack-size+) 'full)
>          (t 'normal)))
>
> It is now straightforward to use stack-state in a filter named :state
> for the typical stack operations.
>
> (define-filtered-function stack-push (stack value)
>    (:filters (:state #'stack-state)))
>
> (define-filtered-function stack-pop (stack)
>    (:filters (:state #'stack-state)))
>
> (define-filtered-function stack-emptyp (stack)
>    (:filters (:state #'stack-state)))
>
> We can now group the behavior of a stack according to its different
> states. Note that for 'normal' state, we do not need to mention the use
> of any filter here, because the methods are not specialized on anything
> specific anyway. (Filtered functions always allow for 'regular' methods
> alongside the filtered methods.)
>
> ;;; Normal state
>
> (defmethod stack-push (stack value)
>    (setf (aref (stack-contents stack)
>                (stack-index stack))
>          value)
>    (incf (stack-index stack)))
>
> (defmethod stack-pop (stack)
>     (decf (stack-index stack))
>     (aref (stack-contents stack)
>           (stack-index stack)))
>
> (defmethod stack-emptyp (stack)
>    nil)
>
> ;;; Empty state
>
> (defmethod stack-pop :filter :state ((stack (eql 'empty)))
>    (error "Stack is empty."))
>
> (defmethod stack-emptyp :filter :state ((stack (eql 'empty)))
>    t)
>
> ;;; Full state
>
> (defmethod stack-push :filter :state ((stack (eql 'full)) value)
>    (error "Stack is full."))
>
> Note that we used a derived state function here, that determines the
> state of the stack based on some of its other properties. Since filter
> functions can be any functions, we could also use the reader of a slot
> as a filter function, and thus have the behavior of a filtered function
> depend on the explicit state of an object.
>
> Filtered functions can do a lot more: As already mentioned, they can use
> more than one filter; filter functions can see all the arguments a
> generic function receives; and filters can be guarded, which means that
> methods that use a particular filter may be completely ignored if the
> arguments don't fulfil a certain predicate. You can read the paper
> "Filtered Dispatch" athttp://p-cos.net/documents/filtered-dispatch.pdf
> that I co-authored with Charlotte Herzeel, Jorge Vallejos and Theo
> D'Hondt for a more thorough introduction, background information and
> semantics, and which also includes an extensible metacircular Lisp
> interpreter as an example, based on implementing EVAL as a filtered
> function.
>
> Pascal
Any ideas where those would be useful? ContextL was interesting but I
never figured a natural problem where to use it.

Bobi

 |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11
Prev: [ANN] Filtered functions
Next: Filtered functions.