Some notes

Alex Martelli aleaxit at yahoo.com
Sat Oct 16 14:34:30 CEST 2004


Scott David Daniels <Scott.Daniels at Acm.Org> wrote:

> Alex Martelli wrote:
> > [lotsa stuff I like]
> >>>- The functional IF seems interesting, like:
> >>>if(cond, code1, code2) ... (Or ... a different syntax, [allowing elif])
> >>Many variants have been proposed over the years, but none have ever made
> >>it in.
> > I think generators could get us close to this kind of thing (in Py3k).
> > 
> > They'd have to sprout a new method 'skip', similar to 'next' but defined
> > to not evaluate the argument of the next yield. 
> That seems pretty tough to define.  for a generator like:
>      def agen():
>          source = open('somedatafile.txt')
>          for i in range(1000):
>              source.seek(4 * i**2 + 33 * i + 52)
>              line = source.readline()
>              if line.startswith('magic:'):
>                  yield line[6:]
>          source.close()
> 
> What computation would "skip the evaluation of the next yield" avoid?

Just the 'line[6:]' slicing, for definiteness.  I don't see anything
hard to define about it.  Just conceptually turn each 'yield XXX' into:
    if _must_skip_next_yield: yield None
    else: yield XXX
with local flag _must_skip_next_yield being automatically set to False
when .next() is called on the iterator object, set to True when .skip()
is called.
    

> > ...  Such functions as lisp's cond might then easily be implemented:
> > 
> > def cond(@_args):
> >     for test in _args:
> >         if test: return _args.next()
> >         else: _args.skip()
> 
> what would be different between this and:
> 
>  > def cond(@_args):
>  >     for test in _args:
>  >         if test: return _args.next()
>  >         else: _args.next()

Your alternative evaluates every item in the _args iterator, and thus is
completely useless for cond's "guarding" purposes.  E.g.,

inverse = cond(x, 1.0/x, True, None)

would raise a ZeroDivisionError under your alternative, would just set
inverse to None under my proposal.

 
> I just don't understand the semantics of .skip().

Maybe it was too obvious to me so I failed to specify it in detail.

An example iterator that just does selective evaluation in a sequence:

def someof(sequence):
    for i in xrange(len(sequence)):
        if _must_skip_next_yield: yield None
        else: yield sequence[i]

with the same semantics for the special flag _must_skip_next_yield.
Alternatively, if a sequence's iterator also implemented skip:

def someof(iterable):
    it = iter(iterable)
    assert has_attr(it, 'skip')
    while True:
        if _must_skip_next_yield: yield it.skip()
        else: yield it.next()

this would be essentially a "no-op" wrapper of iterable, essentially
identical to iter(iterable), and I'm just showing it to further
illustrate the intended semantics of 'skip'.

The iterator over arguments, which I propose, could not be implemented
in Python today (Python today has no way to collect yet-unevaluated
arguments).  I do believe that the C interpreter would need few changes
to implement it (what syntax to use to signal it being the one
contentious part), and even fewer to accept a .skip method on generators
and use it to set a local variable _must_skip_next_yield in the
generator's frame (not particularly useful, I believe -- not all
iterators would have to be skippable, and, unless strong use cases
emerge, normal generators might well be deemed nonskippable ones).


Alex



More information about the Python-list mailing list