Function Specializers 
Author Message
 Function Specializers

I propose that Dylan support articulation of functional
types to help programmers promote efficiency, in a type
safe manner, where methods are passed as arguments.

Beyond the syntax for specifying the argument and value
types of a method: there does not appear to be a syntax
for specializing bindings to these methods.  Functional
type specializers might have been supported, as follows:

define method caller
    ( fun-arg::( fun-in::<U> ) => ( fun-out::<V> ), ... )
 => ( max-output::<V> );
  let min-input::<U> = ... ;
  fun-arg( min-input );
end method caller;

Dylan must currently admit any method object for an argument
specialized as <FUNCTION>, without regard for restriction on
argument or value type components that might be expressed at
compile time.  Perhaps LIMITED() could be extended: to allow
the argument and value types to further specialize arguments
of type <FUNCTION>.



Sat, 20 Mar 1999 03:00:00 GMT  
 Function Specializers

Quote:

> I propose that Dylan support articulation of functional
> types to help programmers promote efficiency, in a type
> safe manner, where methods are passed as arguments.
[...]
> Dylan must currently admit any method object for an argument
> specialized as <FUNCTION>, without regard for restriction on
> argument or value type components that might be expressed at
> compile time.  Perhaps LIMITED() could be extended: to allow
> the argument and value types to further specialize arguments
> of type <FUNCTION>.

I've wondered about this myself, and I agree it seems a natural addition to
the language. I'd like to know if there are any arguments against it.

...........................................................................
Chris Page
Software Wrangler                  This message was created using {*filter*}dog

http://www.*-*-*.com/ ~page/
...........................................................................



Sun, 28 Mar 1999 03:00:00 GMT  
 Function Specializers

Quote:


>> I propose that Dylan support articulation of functional
>> types to help programmers promote efficiency, in a type
>> safe manner, where methods are passed as arguments.
>[...]
>> Dylan must currently admit any method object for an argument
>> specialized as <FUNCTION>, without regard for restriction on
>> argument or value type components that might be expressed at
>> compile time.  Perhaps LIMITED() could be extended: to allow
>> the argument and value types to further specialize arguments
>> of type <FUNCTION>.

>I've wondered about this myself, and I agree it seems a natural addition to
>the language. I'd like to know if there are any arguments against it.

  First problem is that the class <function> is an abstract class.
  Invoking LIMITED on an abstract class is probably a bad idea.
  [ It is invalid on <collection> for this reason. ]
  The class <generic-function> is instantiable, but <method> is kind of
  fuzzy.

  The above aside the keyed args to the above LIMITED should probably be in
  a compatible form of what FUNCTION-SPECIALIZERS, FUNCTION-ARGUMENTS, and
  FUNCTION-RETURN-VALUES return.

  Second "problem" is that can't be totally checked at compile time.
  Functions are first objects so the function being passed may not even
  exist at compile time.  Therefore it must be checked dynamically.
  For instance

  define constant  foo = method ()  
                                method( a :: int , b :: int )
                                        ...
                                end
                        end;

  defin constant   alt_foo = method () => ( result :: <function> )
                                method ( a :: int , b :: int )
                                        ...
                                end
                             end;

  define constant  bar = method ( m :: <function> )
                                m ( 5 , 5 );
                         end ;

  bar( foo()) ;  // works, but deny because not "explicit" enough?
                // definately could perhaps issue pedantic warning though.

  bar( alt_foo() );  // works

  bar( foo );   // doesn't work, runtime error.

--

Lyman S. Taylor                 "Because no matter where you go,

                                                Buckaroo Banzai



Fri, 02 Apr 1999 03:00:00 GMT  
 Function Specializers



Quote:



>>> I propose that Dylan support articulation of functional
>>> types to help programmers promote efficiency, in a type
>>> safe manner, where methods are passed as arguments.
>>[...]
>>> Dylan must currently admit any method object for an argument
>>> specialized as <FUNCTION>, without regard for restriction on
>>> argument or value type components that might be expressed at
>>> compile time.  Perhaps LIMITED() could be extended: to allow
>>> the argument and value types to further specialize arguments
>>> of type <FUNCTION>.

>>I've wondered about this myself, and I agree it seems a natural
addition to
>>the language. I'd like to know if there are any arguments against
it.

>  First problem is that the class <function> is an abstract class.
>  Invoking LIMITED on an abstract class is probably a bad idea.

#########################
Why that?
By definition (DRM p. 251) limited(singleton(<some-class>), ...)
simply
returns a (runtime) subtype of <some-class> restricted by the
constrains given
with "...".

Quote:
>  [ It is invalid on <collection> for this reason. ]

#########################
limited(singleton(<collection>), size: n, of: <element-class>)  is
explicitly allowed!
(see p. 201 and 251 DRM.) It means "Give me a subtype of <collection>
that is
capabable of storing a number n of <element-class> objects. They can
be accessed
in the same way you access elements of <collection>.

Quote:
>  The class <generic-function> is instantiable, but <method> is kind
of
>  fuzzy.

#########################
You can instantiate <method>s implicitly by writing "method () .. end"
in your
Dylan program. You can clone them too. You are right in the aspect,
that you
cannot (by standard language means) instantiate a <method> by passing
it as
the first argument to make. In order to do that, one would have be
able to also
pass a machine function pointer to make too. That would not --of
course--
be portable! I could also imagine to pass a string containing some
verbatim
Dylan source, that would be compiled or interpreted some way. Since
Dylan
has no standard eval, this wouldnt be portable either. Extensions
could also
instantiate a <method> with make by providing some java etc. method
object.

Quote:

>  The above aside the keyed args to the above LIMITED should probably
be in
>  a compatible form of what FUNCTION-SPECIALIZERS, FUNCTION-
>ARGUMENTS, and
>  FUNCTION-RETURN-VALUES return.

#########################
I  agree. One could introduce limited <function> types with this
syntax:

        let >f< :: <type>  = limited(<function>, specializers: #(spec1, ..
, specn)
                        [results: #(rspec1, .. , rspecm)]);     // [] means optional

Instances of >f< would be functions with the prescribed specializers
and results.
Subtypes of >f< would be the more specific specializer and result
constellations.
Of course specializers: would only match with the positional arguments
of the function.
Since Dylan requires that functions are introspective with respect to
their specializers
and results (see p. 230, 341, 343 DRM), instance?(>f<, foo) can be
proven at runtime.

- Show quoted text -

Quote:
>  Second "problem" is that can't be totally checked at compile time.
>  Functions are first objects so the function being passed may not
even
>  exist at compile time.  Therefore it must be checked dynamically.
>  For instance

>  define constant  foo = method ()  
>                            method( a :: int , b :: int )
>                                    ...
>                            end
>                    end;

>  defin constant   alt_foo = method () => ( result :: <function>
)
>                            method ( a :: int , b :: int )
>                                    ...
>                            end
>                         end;

>  define constant  bar = method ( m :: <function> )
>                            m ( 5 , 5 );
>                     end ;

>  bar( foo()) ;  // works, but deny because not "explicit" enough?
>            // definately could perhaps issue pedantic warning though.

>  bar( alt_foo() );  // works

>  bar( foo );   // doesn't work, runtime error.

#########################
Compile-time type checking is a nice thing but it is not at all
required in Dylan.
You can add methods with arbitrary specializers to a generic function.
They will
be proven and dispatched at runtime. Compile-time known types can
speed up
this process.
Singletons as specializers are typically also subject to run-time
checking in the
above context.

        Gabor



Fri, 09 Apr 1999 03:00:00 GMT  
 Function Specializers

this is a followup to my previous message. If you did not like that,
simply skip this, since you will not like it ;-)

Im just working on a simple minded Dylan implementation, and since
Im
just arrived at the subject of types, I would like to make some
suggestions and
receive feedback/comments.

First Id like to introduce a new function "partial" that is thought
to create
new Dylan types, i. e. (indirect) instances of <type>.:

I wonder whether the concept of singleton and union types can be
extended in a reasonable way.

Consider this:

        define method fak(n :: <integer>)
                n * fak(n - 1);
        end;

        define method fak(n :: singleton(0))
                1;
        end;

What does "n :: <integer>" stand for? It means: take an object, name
it "n" and if it
is an integer then consider the enclosing method as applicable.
Similarly "singleton(0)" stands for compare n with 0 (==!) and use
this method if true.

To put it another way, there is a conceptual "decision predicate" that
rules
whether the method is applicable.
In the first case this would be "instance?(n, <integer>)", and in the
second "n == 0".

Now introduce the generic concept:

One could define new types on base of an arbitrary predicate function:

define constant >odd-integer< :: <type> = partial(method(i ::
<integer>) i.odd? end);

the instance? test for any <integer> is clear:
instance?(n, >odd-integer<)  <=> (method(i :: <integer>) i.odd?
end)(n)

The subtype? test is somewhat trickier:
the base type of >odd-integer< would be <integer>, since the predicate
is
defined on this type. An optional #key argument "base: :: <type>"
could
override this assumption. One could infer the base type by
"function-specializers(predicate)[0]".

The obvious constraints would apply to the number of specializers
of the predicate and its result type (<boolean>) and to the
permitted "base:" argument.

Now lett play with that somewhat:

        define method erasthotenes(i :: >odd-integer<)
                // just sieve i here ;-)
        end method;

        define constant >eras< = partial(erasthotenes);   // I cannot recall
whether this is
                                                                                // the mathematical definition
                                                                                // of pseudo-primes?
                                                                                // (have a look into van der Waerden)

or:

        define constant >unit< = partial(method(c :: <complex>) c.abs = 1
end);

even nicer version of >odd-integer< is:

        define constant >odd-integer< :: <type> = partial(odd?);

since odd? takes <integer>s.

You get the message, what is going on here is the Dylan analogy to
the mathematical subset notation:

        {c ? C | |c| = 1}               (sorry for the special font but I dont think
TeX is more readable :-)

Now its time to refine the concept:
Imagine this:

        define constant >colleagues< = partial(method(h)
                                                                member?(h, #(#"martin", #"jens", #"claus", #"dodo"))                                                    
end);

Quote:
>colleagues< would be equivalent to

        type-union(singleton(#"martin"), singleton(#"jens"),
                                singleton(#"claus"), singleton(#"dodo"))

A better notation would be:
        partial(#(#"martin", #"jens", #"claus", #"dodo"))
with a collection as first argument.

This way one could expressively write down explicit sets.

The compiler could infer the equivalence of the above three types,
since
"singleton", "partial", "type-union", "member?" and "=="
are all functions completely known at compile-time
and their arguments are literal constants.

Subsumming the above, the declaration of partial (with proposed syntax
from previous message) would be:

        partial(pred :: limited(<function>, specializers: 1, results:
#(<boolean>))
                        #key base :: <type>) => part :: <type>

        partial(set :: <collection>, #key comp :: <function> = \==)
=> part :: <type>

        Just thinking...

                Gabor

P.S.: A better name for "partial" is welcome.



Fri, 09 Apr 1999 03:00:00 GMT  
 Function Specializers


Quote:

>>  First problem is that the class <function> is an abstract class.
>>  Invoking LIMITED on an abstract class is probably a bad idea.

>#########################
>Why that?
>By definition (DRM p. 251) limited(singleton(<some-class>), ...)
>simply
>returns a (runtime) subtype of <some-class> restricted by the
>constrains given
>with "...".

  This is kind of strange. Also on p. 251 it says that
        singleton object => singelton  

  Namely that the function singleton returns a value that is an
  instance of <singleton>.  Now on p. 189 you will find that the
  superclass of <singleton> is <type>.  The superclass of <class> is
  also <type>.  However, this does not make a <singleton> a subtype of <class>.

  OK back to page 251....
                        limited class #key => type

        arguments: class  an instance of <class>

  Now if I wanted to add methods to generic function  "limited" you could
  ( if you could add to the DYLAN library that is. :-) ) say...

        define method limited (  x == <some-class> .... )  

  or
        define method limited (  x :: singleton(<some-class>) ... )

Quote:

>>  [ It is invalid on <collection> for this reason. ]

>#########################
>limited(singleton(<collection>), size: n, of: <element-class>)  is
>explicitly allowed!
>(see p. 201 and 251 DRM.) It means "Give me a subtype of <collection>
>that is
>capabable of storing a number n of <element-class> objects. They can
>be accessed
>in the same way you access elements of <collection>.

   Errr, go onto p. 252 and you will find the following sentence.

    "These methods return uninstantiable limited collection types."

   OK so I was incorrect that you can't invoke limited on <collection>
   ( ignoring the whole singleton vs. "just raw class" thing ). However,
   you can't instantiate it. You'll note that all of those classes
   above are abstract.  Since <function> is an abstract class, to be
   consistant, you shouldn't be able to instantiate it either.

   Since it isn't instantiable then you'll have to do a type check at
   runtime to see if this a <generic function> or a <method>. Which will
   add one more step of indirection.

   However, I suppose limited ( <method> ... ) wouldn't have this problem.
   Or <generic-function>... i'm not sure being able to do  this on
   <function> is all that wise/useful.
   [ Of course I'm perplexed as to what sort of optimization you could
        do with the type:
                limited( <collection> , ofsize: n )
        either. Well I guess is the system had big-integers too and
        you wanted a constrait on n being some small-integer. ]

Quote:

>Since Dylan requires that functions are introspective with respect to
>their specializers

  Yeah but in normal method dispatch this sort of introspections isn't
  needed. You simply have to ask whether the type of each argument is in
  the proper subsets of types precribed by the specializers.  This is
  a deeper introspection. Not only does the type have to match the type,
  but also some internal datastructure in the object must also match up.....
  which is kind of stretchy things a bit.....in my opinion.
  I could be wrong but a limited type of this kind would require something
  different from the normal dispatching routine(s).  Alas it isn't too
  different from the deep introspection of a vector to discern it only
  contains integers so I guess it is on the same slippery slope.

  Perhaps a pragmatic problem is that def
  Furthermore are modules at compile time required to check the types
  of the values attached to the imported symbols?  I thought if module
  A exported the symbol FOO and module B imported and used FOO that the
  fact that there was an args mismatch only had to be catch before the
  method body was entered ( either at compile time or at run time).

Quote:
>>  define constant  foo =3D method ()  
....

>Compile-time type checking is a nice thing but it is not at all
>required in Dylan.

    yeah but to maybe get compile time error messages your looking for
    I'd have to

    define constant <fcn-no-args> = limited( <function> ) ;
    define constant foo :: <fcn-no-args> = method () .... end ;

   and automagically

        define generic mumble ( ) ;

        define method mumble ( ) ... end;

   would have to create an equivalent type. which would be used to type
   the <generic-function> instance for mumble and each of the methods
   added to it.  Or better still a limited on <generic-function> with no
   args.  for the generic and a limited <method> with no args on the methods.
   The symbol mumble gets typed with <function> with no args.

   [ currently I guess implementation put the type <function> ]

Quote:

>You can add methods with arbitrary specializers to a generic function.
>They will

>be proven and dispatched at runtime. Compile-time known types can
>speed up

>this process.

    Err I'm not so sure about this. In CLOS the types of the specializers
    are known at compile time and you still can't automagically leap to
    the right place in the dispatch table using some optimized multi-method
    dispatch schemes.  

    The dynamic updating of the number of classes and of the applicable
    methods of generic functions at run time, also makes doing this all at
    compile time not work so well. So even if you know the types of the
    objects being dispatched on at compile time there may be dynamic info
    associated with the type(s) that is used for locating the most applicable
    method in the dispatch table.  Although perhaps dynamically added
    classes, methods could be relegated to second class status to gain
    a bigger speed increase for stuff known at compile time.

--

Lyman S. Taylor                 "Because no matter where you go,

                                                Buckaroo Banzai



Sun, 11 Apr 1999 03:00:00 GMT  
 Function Specializers

Well, it's time to clean some things up...

first I'd like to apologize to all those who don't have a MIME capable
newsreader and have received my previous posts cluttered with ugly
hieroglyphes. (Since I always read back everything the same way I sent,
I would have never realized this problem if I hadn't got an email on
this issue. -- thanks) --- breathe !now!

It seems that the structure of thoughts is not isomorphic with the
frac-dimensional data type of these newsgroup messages (1 < frac < 2).



Quote:
>>By definition (DRM p. 251) limited(singleton(<some-class>), ...)
>>simply
>>returns a (runtime) subtype of <some-class> restricted by the
>>constrains given
>>with "...".

>  This is kind of strange. Also on p. 251 it says that
>    singleton object => singelton  

>  Namely that the function singleton returns a value that is an
>  instance of <singleton>.  Now on p. 189 you will find that the
>  superclass of <singleton> is <type>.  The superclass of <class> is
>  also <type>.  However, this does not make a <singleton> a subtype of

<class>.

Well the DRM uses some abbreviated syntax description (in order to
improve readability? :-) that might be confusing at first, but better on
the long term. As I see it, the excerpt taken from p. 251:
"limited(singleton <integer>) #key min max => type"
means (well I was somewhat sloppy with the exact typography...):
"the method (inside the GF limited) that will be executed when the GF
is given the variable named <integer> as its first argument"
other formulation: this method specializes on the particular object
<integer>.

in Dylan code you invoke this method by writing
        limited(<integer>, min: 6 max: 444);

The GF limited takes an object -which is a class- as its first argument
(i.e.
instance?(object, <class>) is true). The following arguments are keyword
arguments (i.e. alternating a <keyword> and a value).
It happens that the variable named <integer> has the type <class>,
thus the restriction imposed by the declaration of the GF is met.

This way you create a new Dylan type (or specializer):
        define constant spec = limited(<collection>, of: <complex> size: 234);
Now you can use "spec" instead of the lengthy expression above as a
specializer of a method you create:
        define method foo(cplex-coll :: spec)
                /// stuff here
        end

This method (as a member of the implicitly defined GF "foo" that is
specialized on <object>s -- i.e. everything in Dylan) will only be invoked
if you provide the GF an object that is a collection and has 234 instances
of <complex> objects in it.
Of course "spec" will not be instantiable, but you can create limited
arrays
that hold 234 complex numbers with "make":
        make(limited(<vector>, of: <complex> size: 234 fill: 0))

This is the language definition, how it carries over to an effective
implementation is another issue...

In order to verify that cplex-coll is an instance of spec, at runtime
some constraints have to be checked:

a)      does the collection cplex-coll hold exactly 234 elements?
b)      are those elements all instances of <complex>?

this is indeed quite costly. The programmer has to be aware of that in
order
to write effective code. However limited(<vector>, of: <complex> size: 234)
should be an easy type to recognize if the implementation uses several
subclasses of <type> internally.

Since that is enough for today, I stop, in the hope everything is clearer
now
(I could make some comments on the rest of the message in the span of this
week).

        Gabor

PS: the morale of this post is that the ability to use styled text in
discussions would reduce potential misunderstandings and bandwidth. So the
MIME newsreader is a good idea after all.



Sun, 11 Apr 1999 03:00:00 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. each-subclass slot specializer working examples?

2. boolean as method specializer

3. CLOS Help: custom parameter specializers for methods?

4. VC++ calling fortran function and fortran function calling a c++ function

5. Calling functions from functions from functions ...

6. converting C++ Function to Clarion 5 Function

7. Replace standard MESSAGE function in C4 with own message function

8. Clarion function prototypes for SPGP pgp wrapper functions

9. What might be equivalent clarion function for vb function IIF()

10. counter function : How works the Set attribute function

11. VI Logger functions dont appear on Labview Function Palettes

12. Passing variables to user functions of Clipper functions

 

 
Powered by phpBB® Forum Software