1

I have a function my_algorithm of the following form:

  • iteratively generate some items
  • call an abstract inner_fn on each item
def my_algorithm(*args, inner_fn, **kwargs):
    for ...: # many nested loops go here
         inner_fn(next_item) # call monitor on each item

Hence my_algorithm represents an "outer algorithm" with its inner behavior parametrized into inner_fn.

An alternative way to abstract the inner behavior away would be to use a generator:

def my_algorithm_iter(*args, **kwargs):
    for ...: # many nested loops go here
        yield next_item

Both concepts provide different user interfaces, that is

my_algorithm(*a, my_inner_fn, **kw)

vs.

for item in my_algorithm_iter(*a, **kw):
    my_inner_fn(item)

To offer both iterfaces without code duplication, one could define my_algorithm by means of my_algorithm_iter as follows:

def my_algorithm(*agrs, inner_fn, **kwargs):
    for item in my_algorithm_iter(*args, **kwargs):
        inner_fn(item)

I was wondering, if there is also a simple solution for the reverse, expressing my_algorithm_iter by means of my_algorithm.

flonk
  • 3,726
  • 3
  • 24
  • 37
  • 1
    I don't understand. Do you mean to implement `my_algorithm_iter` in terms of `my_algorithm`? I don't think there is any clean way to do that for one simple reason: `my_algorithm` is completely *eager*, while `my_algorithm_iter` is lazy. It's easy to transform a lazy function into an eager one (you just consume it), however it's basically impossible to make an eager function lazy. So the best you can have is have `somelist = []` and call `my_algorithm(..., inner_fn=somelist.append); yield from somelist` which is still eager. – Bakuriu Jun 01 '19 at 10:51
  • @Bakuriu Thank you, I will have a look at the concepts of *eager* vs. *lazy* functions, I never heard about *eager* functions before. – flonk Jun 01 '19 at 10:59
  • @Bakuriu Yes, I asked for "expressing `A` by means of `B`" which is almost what you say "implement `A` in terms of `B`". – flonk Jun 01 '19 at 11:01
  • Generator functions with `yield` are pausable, regular functions with callbacks are not - pausibility is a key property of a lazy producer. To pause a regular function, you need to use threads. See the linked duplicate for [my answer](https://stackoverflow.com/a/57236093/102441) – Eric Jul 27 '19 at 21:09

0 Answers0