http://www.perlmonks.org?node_id=734280


in reply to Re^4: IO::Lambda: call for participation
in thread IO::Lambda: call for participation

You're welcome.

I have some follow-up thoughts, now that IO::Lambda has been rattling around in my head for a few hours. Mostly it relates to how I'd try to explain it to someone. Is this explanation correct:

That's my rough take on it. I think I'm being a little imprecise around the definition of "predicate" as you seem to indicate that lambda() is also a predicate. I remember enough of HOP to know why. In a way, predicates just define conditions under which callbacks are to be run. The lambda() function returns a lambda that can only be run explicitly with a method call. The other predicates use the context to provide sugar for automatically running the callback under certain conditions.

Also, explaining what gets returned from running a lambda really needs a lot more explanation and some examples. Otherwise, I'd be tempted to use a global to make sure each callback put its output in the right place so I didn't have to worry about what happens inside the black box.

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Replies are listed 'Best First'.
Re^6: IO::Lambda: call for participation
by dk (Chaplain) on Jan 05, 2009 at 21:51 UTC
    A IO::Lambda object (a "lambda") is an FSM generator

    That is correct.

    Lambdas are executed using method calls to the lambda, such as call(), wait(), etc. (as described elsewhere). (In what circumstances would I want to use one method or another?)

    That too is correct. You would usually use wait(), or rather even wait(@args), that passes @args to the very first callback associated with lambda (where these are seen as @_), starts the lambda, and waits for its execution. However, call(@args) only stores the arguments, but does nothing about execution. Such pre-initialized lambda can still be awaited by wait(), which doesn't clear @args if no arguments were passed to it. Basically, $x-> wait(@args) is same as $x-> call(@args)-> wait. Also, wait_any() and wait_all() operate more than on one lambda; these functions do not pass arguments at all.

    I also like to juxtapose synchronous and asynchronous ways of executing lambdas. wait() and friends are synchronous. tail() etc functions are asynchronous. There are even pairs that do the same in sync and async modes: wait() and tail(), wait_for_all() and tails(), wait_for_any() and any_tail().

    Within the initialization callback, special functions called "predicates" register a callback in response to specific events. .. Predicate callbacks may also call predicates

    These two are also correct.

    Some predicates may have side effects in addition to registering an event callback.

    I wouldn't call it side effect, I think of it rather as a syntactic sugar. That is because tail(@args) can pass arguments to a lambda, and there's no point in passing arguments to an already running lambda. I agree that it looks like a side effect when you explicitly don't want to start a lambda that is already finished, but that is what autorestart() method is for.

    As for the predicates, as you say, they "just define conditions under which callbacks are to be run". And that is one of the ways to put it, correctly and tersely, without resorting to vocabulary of functional languages. That is though a challenge on its own, to coin simple but understandable descriptions for sophisticated concepts.

    Also, explaining what gets returned from running a lambda really needs a lot more explanation and some examples

    I see. Result of running a lambda is whatever the last executed callback has returned. This is simple for linear execution, f.ex. if

    my $x = lambda { context 1; sleep { return 42 } };
    then $x->wait returns 42. Pipelining also works in the similar vein:
    my $y = lambda { context $x; tail { return @_ } };
    $y-> wait returns 42 too. However, things get interesting when $y waits for $x and $z and $t, where the order of execution is not known. Nevertheless, it is the last result that gets returned.

    This uncertainty is partially addressed in tailo(), an "ordered" version of tails(). Where tails() returns results of lambdas in the order of their completion, tailo() keeps the order of the lambdas as they were stored in the context.

Re^6: IO::Lambda: call for participation
by zby (Vicar) on Jan 05, 2009 at 22:29 UTC
      The word "predicate" was used here not in logical terms, but vaguely refers to the term used in (functional) programming. The origin of the term was though largely stemmed from perl. Perl functions map, grep, and sort, for example, receive their first argument a special function, and a list of arguments. In functional programming, these mapping functions (callbacks, not map/grep themselves) are sometimes called predicates.

      In Io::Lambda, functions like sleep() and tail() are declared very similarly. They also accept a function and a list of arguments. The only semantic difference is that the label "predicate" has moved away from the callback to the function itself. That possibly questions if the choice of the word itself was appropriate, however, I couldn't find a better one.

        Hmm - the callback to 'grep' is a predicate in the sense used in mathematical logic (a function that takes an element and returns true of false), the others (for map and sort) are not. This is your choice - but I would at least verify in your sources if indeed all the callbacks are called predicates, I googled for the term and I cannot find such a usage of it (for example the Merriam-Webster dictionary definition is very close to the mathematical one).