[Types-sig] types, functional stuff.
Edward Welbourne
Edward Welbourne <eddy@chaos.org.uk>
Thu, 3 Dec 1998 19:54:53 GMT
A quick suggestion on the `how to specify static typing' debate ... then
a little contribution on functional tools.
Once upon a time, so I'm told, folk started putting
__doc__ = """The documentation of this entity"""
at the starts of entities, and it was seen to be good.
OK, so a function (or method) can start with
def myfunc(first, flexible, optional=7):
__statictypingdata__ = {
'': types.IntegerType, # The return type
'first': types.FloatType, # The type of this arg
'flexible': (types.StringType, types.TupleType, types.ListType),
# that's offering a choice
'optional': (None, types.IntType), # NB None != NoneType
# and there's nothing to stop us putting in info about local
# variables, too.
}
and a class implementing .__call__() could do similar.
The big problem is specifying that a dictionary argument is to be a
dictionary mapping integers to objects of class Hubert.
This just seems much more practical than whacky syntax.
Now, John Skaller asked for:
> compose(f1, f2, f3, f4 ..) # chain in series, 1 arg only
> product(f1, f2, f3, f4, ..) # apply componentwise (in parallel)
> sum(f1, f2, .. ) # select one of
> delta(x,i) = (x,x,x,x,x ..) # i times
so, John: there follow implementations for 3 of these in python (you can
do currying too, it's not hard). Use them. If the uses persuade folk
they are useful, maybe someone'll bother to implement them as a C
module. The language doesn't need them as built-ins. I haven't done
sum: it would involve working out what types the functions f1, ... take
as their arguments and I don't have time or the right docs to hand.
But hey, I'll throw in a close relative (union).
def delta(what, count=2): return (what,) * count
class compose:
def __init__(self, *args):
row = []
# this will be in reverse order so that
# compose(f1,f2)(x) = f1(f2(x))
for item in args:
if isinstance(item, _Composite):
# gratuitous optimisation
row = item.__components + row
else:
row[:0] = [ item ]
self.__components = row
def __call__(self, *args):
for item in self.__components:
args = apply(item, args)
if type(args) != types.TupleType: args = (args,)
return args
# yeah, sorry about returning a tuple always.
class product:
def __init__(self, *args):
self.__factors = args
def __call__(self, *args):
if len(args) != len(self.__factors):
raise TypeError, 'Wrong number of arguments'
return map(lambda f,x: f(x), self.__factors, args)
class union:
def __init__(self, parts):
"""parts is a dict, mapping types to functions"""
self.__parts = parts
def __call__(self, what):
try: part = self.__parts(type(what))
except KeyError:
raise TypeError, 'Argument not supported by this direct sum'
return part(what)
and no, I haven't tested them: I just typed them out of my head. The
basic lesson is that python is a perfectly good implementation domain
for all the functional things I ever want. They practically write
themselves, so don't complain about their absence from the language.
(But lambda is a necessity !)
I'm not subscribing to this list, just reading web archive when I have time.
So don't be offended if I'm slow responding to any replies ;^)
Dig the crazy meta-stuff, but it confuses me !
Eddy.