1

How can Continuation-passing style be facilitated from Python?

(I think that's the right term)


My code is starting to get messy, I have map, filter and chains of lambdas like so:

(lambda a,b: (lambda c:(lambda d: d*d)(c-b))(a*b))(5,6)

"Pipeline expressions" are found in a variety of languages, for example:

F# solution (e.g.: |>)

let complexFunction =
    2                            (* 2 *)
    |> ( fun x -> x + 5)         (* 2 + 5 = 7 *)
    |> ( fun x -> x * x)         (* 7 * 7 = 49 *)
    |> ( fun x -> x.ToString() ) (* 49.ToString = "49" *)

Haskell solution (e.g.: do, pipes)

 main = do
     hSetBuffering stdout NoBuffering
     str <- runEffect $
         ("End of input!" <$ P.stdinLn) >-> ("Broken pipe!" <$ P.stdoutLn)
     hPutStrLn stderr str

JavaScript (e.g.: async.js):

async.waterfall([
    function(callback) {
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback) {
      // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback) {
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
    // result now equals 'done'    
});

However I understand that this last strategy is more for asynchronous function response resolution (see: callback hell).

How do I present all stages of my processing in a single Python expression/line?

Community
  • 1
  • 1
A T
  • 13,008
  • 21
  • 97
  • 158
  • There is a module [Pipe](https://github.com/JulienPalard/Pipe). But for asynchronous execution you will need something like [Twisted](https://twistedmatrix.com/trac/). – myaut Mar 20 '15 at 09:26
  • @myaut: Async.js was just an example, maybe I'll replace it with F# and Haskell examples to be clearer. – A T Mar 20 '15 at 09:32
  • @AT Doing your Python example won't gain much readability, as the definition of the second lambda cannot be moved out of the definition of the outermost lambda because it depends on `b`. – Carsten Mar 20 '15 at 09:38
  • Couldn't you problem being solved by implementing simple [_fluent interface_](https://en.wikipedia.org/wiki/Fluent_interface)? – myaut Mar 20 '15 at 09:42
  • i would say - don't try to write haskell in python, it's not going to be nice, if you state the problem you're trying to solve i'm sure someone will able to help you – user3012759 Mar 20 '15 at 10:27

1 Answers1

2

AFAIK, there is no standard feature in Python to do that.

There is module called Pipe which overrides operator |, but it is reasonable considered harmful (overriding operator while changing its semantics).

However, you may implement simple Fluent interface for that. Here is an example:

class P:
    def __init__(self, initial):
        self.result = initial

    def __call__(self, func, *args, **kwargs):
        self.result = func(self.result, *args, **kwargs)
        return self

    def map(self, func):
        self.result = map(func, self.result)
        return self

    def filter(self, func):
        self.result = filter(func, self.result)
        return self

    def get(self):
        return self.result

x = P(2)(lambda x: x + 5)(lambda x: x * x)(lambda x: str(x)).get()
z = P(range(10)).map(lambda x: x * 3).filter(lambda x: x % 2 == 0).get()
print(x, list(z))       # prints 49 [0, 6, 12, 18, 24]
myaut
  • 11,174
  • 2
  • 30
  • 62