in reply to regarding 1.02 (was Re: IO::Lambda: call for participation)
in thread IO::Lambda: call for participation
Now, back to your question. "{{" notion is not tied programmatically to the way results are returned, it's just a set of nested closures. However, it is tied conceptually, indeed it means more to a programmer, because it introduces two important parallels between plain old declarative style and all this callback and closure mess.
The first parallel is that the sequence matters. As in normal, blocking code, you would expect programming a HTTP request as
Here, the code is different:print $socket ... readline $socket;
but the sequence is the same! To emphasize this fact, there's no additional indentation for inner closures, to highlight that the execution is top-down, one way, linear.writable { syswrite ... readable { sysread ... }}
This fact, in my opinion, is also a step forward when comparing with programming using the traditional event-driven frameworks, like POE or IO::whatever:
where sequence doesn't (syntactically) matter. One has to deal with sequencing by other means. In IO::Lambda, as in declarative programming, sequence is a part of syntax.on_write => sub { ... }, on_read => sub { ... },
The second parallel is that return quits the scope. In the declarative style, no matter how deep the execution is down in inner cycles, return $x quits the scope of the current subroutine and sends $x to the caller. In IO::Lambda, no matter how many "}}" execution is inside, readable inside writable inside whatever, return $x does basically the same (given of course some restrictions, that no others callbacks are waiting, and no again is called). Whoever awaits for the lambda, be that asynchronous execution by tail/tails/etc, or synchronous by wait, it can count on $x being returned no matter how many stages the lambda internally went through. Again, to compare with the event-driven style, where it's surely possible, but is not that elegant and is not the part of the syntax.
From this parallel one gets an important feature, easy wrapping of lambdas, one inside another. For example, we have a lambda that returns HTTP response, as we just've discussed, created by function http. Let's write a wrapper that accepts not URL and returns plaintext, but HTTP::Request and HTTP::Response:
From here emerges the third parallel, that is about calling one sub inside another: the caller won't care what happens inside the callee. http2 doesn't care how http returns the data. To make it even more clear, let's write a wrapper that understands redirects:sub http2 { my $req = shift; lambda { my $uri = $req-> uri-> as_string; my $host = $req-> uri-> host; my $port = $req-> uri-> port; my $addr = sockaddr_in( $port, inet_aton( $host)); context http( $addr, $uri); tail { my $res = shift; return ( $res =~ /^(\w+ error:)/) ? $res : HTTP::Response-> parse( $res) }} }
(these examples were parts from my talk on yapc::eu, slides (no text sorry) can be found here) )sub http3 { my $req = shift; lambda { context http2($req); tail { my $res = shift; return $res unless ref($res); return $res if $res-> code !~ /^3/; $req-> uri( $res-> header('Location')); context http2( $req); again; }} }
I hope that helps, please ask further if it doesn't.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^2: regarding 1.02 (was Re: IO::Lambda: call for participation)
by merlyn (Sage) on Jan 14, 2009 at 23:46 UTC | |
by runrig (Abbot) on Jan 15, 2009 at 00:28 UTC | |
by dk (Chaplain) on Jan 15, 2009 at 10:47 UTC | |
by dk (Chaplain) on Jan 15, 2009 at 00:33 UTC |