Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re^2: Local for lexicals

by JadeNB (Chaplain)
on Aug 10, 2009 at 23:03 UTC ( [id://787431]=note: print w/replies, xml ) Need Help??


in reply to Re: Local for lexicals
in thread Local for lexicals

Yes, exactly, although I'd also like
$lamb = lambda ( $x, $y ) => sub { $x + $y }
to be such that $lamb->(1, 2) returns 3.

Replies are listed 'Best First'.
Re^3: Local for lexicals
by LanX (Saint) on Aug 10, 2009 at 23:37 UTC
    I think the most productive approach would be to post test code, assuring your intentions are understood, such that other stop posting speculative code...

    Anyway I doubt that your desired "my_local" (or better named "lex-local") is what you need, since $x,$y,$z will always also belong to the outer scope, making ugly side-effects probable!

    { #outer scope $lamb = lambda ( $x, $y, $z ) => sub { $x + $y } }

    the following is simple and very close but lacks the same aliasing like $_[0] does.

      $lamb = sub { my ($x,$y,$z) = @_; $x + $y }

    so using Data::Alias or Lexical::Alias might be what you need to install for lexicals. If you don't wanna install XS-Moduls try working with lex-refs

    DB<20> $lamb=sub { my($x,$y)=\(@_); $$x += $$y } DB<21> $a=10; $lamb->($a,5); print $a 15

    NOTE: Aliasing can always be achieved with * and pack-vars.

    Cheers Rolf

      { #outer scope $lamb = lambda ( $x, $y, $z ) => sub { $x + $y } }
      This is, in a sense, the crux of my problem—I don't want the values of $x, $y, and $z to leak from the inside out, or vice versa, even though they have meaning in the outer scope. In this case, there are many ways around it, which you and others have indicated, but I was just wondering if there was any reason that one had to work around it, or if there were a lex_local that could just be dropped in for lexicals as local can for globals.
      NOTE: Aliasing can always be achieved with * and pack-vars.
      I know about *, although it doesn't seem to do much for lexicals, but what do you mean by pack-vars?
      I think the most productive approach would be to post test code, assuring your intentions are understood, such that other stop posting speculative code...
      (I PM'd you about this, but, on further thought, it seems that there's no reason to keep it P. :-) ) I agree, since it seems pretty clear that I'm not doing a good job of indicating the problem that I'm trying to solve. However, I don't know how to improve. Do you have any suggestions? (This seems almost worthy of being a post in its own right ….)

        Maybe this is a repetition of a question already asked--possibly even asked and answered--but having re-read the thread, I cannot see it. So here goes:

        { #outer scope $lamb = lambda ( $x, $y, $z ) => sub { $x + $y } }

        This is, in a sense, the crux of my problem—I don't want the values of $x, $y, and $z to leak from the inside out, or vice versa,

        What are you trying to achieve that this doesn't?

        my( $x, $y, $z ) = ( 1,2,3 ); my $lamb = do{ my( $x, $y, $z ) = ( $x, $y, $z ); lambda ( $x, $y, $z ) => sub { $x + $y } }

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        or if there were a lex_local that could just be dropped in for lexicals as local can for globals.

        First of all local is the wrong approach, because local just manipulates already declared pack-vars, so under strict you would be forced to predeclare your variables with "our" (or "my") in the outer scope. (look at first our in the following code) (see update)

        I would love to have a lexical local in P5 BUT not with the extra magic of declaring missing variables your assuming.

        What you really want is aliasing like $_[ ] variables do.

        I know about *, although it doesn't seem to do much for lexicals, but what do you mean by pack-vars?

        Aliasing with package-variables

        use strict; use warnings; $\="\n"; my $lamb = sub { our ($d,$e); # local doesn't declare!!! local (*d,*e)=\(@_); $d += $e ; }; our $d="D"; our $u=10; $lamb->($u,5); print $u; #> 15 print $d; #> D

        However, I don't know how to improve.

        from your /msg:

        What can I do to improve? I try to phrase my questions as (1) an informal description of what I want; (2) imaginary code that'll do what I want; (3) descriptions of what I've tried, and what I don't want to do (ideally, with explanations).

        some ideas:

        1. Post working code which exactly does what you want, but in a "unpretty" way. e.g. with
          • $_[0] or
          • lex-refs $$x or
          • aliased pack-vars *x ...
        2. Express what you want to avoid in the working example (uglyness, doubelsigils, pack-vars,...)

        3. Post a test program which proofs every functionality you want to have covered, like
          • aliasing,
          • locality..
        4. e.g. with Test:More like in this post

        5. Write a codegenerator using eval which covers all edge cases e.g.
          • with or without use strict;,
          • with or without use warnings;,
          • variables known/unknown in outer scope,
          • outerscope vars are lex or pack
        6. Make clear which moduls are acceptable to be used...
          • None
          • Just CORE
          • CPAN w/o XS
          • CPAN
          • any

        Cheers Rolf

        UPDATE: as JavaFan pointed out here you are not forced to use our with full-qualified varnames, so this works

        my $lamb = sub { # our ($d,$e); local (*::d,*::e)=\(@_); $::d += $::e ; };
        but I don't know if this meets your criteria of being more elegant than using $_[0] += $_[1] and furthermore it's only a pack-var thing, in P5 lex-vars have no namespaces...
        I know about *, although it doesn't seem to do much for lexicals, but what do you mean by pack-vars?
        Well, of course * doesn't do anything for lexicals, as * is a typeglob. Lexicals don't live in typeglobs. A "pack-var" is just short for "package variable". You know that Perl has two kinds of variables, right? Lexical variables, and package variables (the latter is often confusingly called "global" variables, but that just shows ignorance. A lexical declared on an outer scope is "global" as well - "global" has to do with the broadness of the scope of the variable, not with its flavour).

        I'm still not sure what exactly you want with your "lambda" variables. On the one hand, you seem to use them as named parameters, but that gives them a well defined scope - they are scoped to the subs, and just act as aliases for $_[0], $_[1], etc. OTOH, you seem to be want to set them from way out of their scope (your "localized lexicals" request). That has little to do with lambda functions I've encountered in functional languages (where there's no such thing as assignment or state change).

Re^3: Local for lexicals
by ikegami (Patriarch) on Aug 12, 2009 at 21:00 UTC

    So what you really want are anon subs with named arguments. Have you looked at

    use signatures; my $lamb = sub ($x, $y) { $x + $y }; print( $lamb->(3,4), "\n" ); # 7

    Unfortunately, the following doesn't work

    use signatures; my $lamb = sub ($x) { $x = 4 }; my $y = 3; $lamb->($y); print("$y\n"); # 3 XXX want 4

    I also tried Sub::Signatures and Perl6::Subs. Both accept anonymous subs with named parameters. Neither pass the alias test.

    Maybe one of them can be fixed. Maybe it works with one of the other modules.

    Update: To spend the least amount of effort, your best bet is to fork signatures. It hooks itself into the parser to change

    sub (...) { ... }

    into

    sub { my (...) = @_; ... }

    By changing what gets injected (my (...) = @_;) to something like the following, you can achieve aliasing (which also fixes tied vars):

    Lexical::Alias::alias(my $x, $_[0]); Lexical::Alias::alias(my $y, $_[1]); Lexical::Alias::alias(my $z, $_[2]);

    It might be best to use copying semantics by default, while adding a mechanism to specify aliasing ("is rw"?). That would allow you to extend signatures instead of replacing it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://787431]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (5)
As of 2024-03-28 10:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found