in reply to sort +*, @array

Apparently this is akin to a schwartzian transform ...

How can that possibly be?

Given that the ST allows you to sort the data by a user defined piece of secondary data, and a user-defined comparison strategy -- and that secondary data needn't even be derived from the actual data in anyway -- and that construct clearly has no mechanism for providing either.

For example, how could that construct do this:

my $today = time; $today -= $today % 86400 + 43200;; ## midday my @dates = map $today + 86400 * $_, 0 .. 364;; my @ordered = map $_->[0], sort { $a->[1] cmp $b->[1] || $b->[2] cmp $a->[2] } map[ $_, substr(scalar localtime($_),0,3), substr(scalar localtime($_), +5,3) ], @dates;;

I can't think of any good reason to sort the epoch dates of the next year of days, by the spelling of their days ascending and the spelling of their months descending, but if I wanted to, the ST allows me to do so.

But there is no way that construct will.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
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.
/div

Replies are listed 'Best First'.
Re^2: sort +*, @array
by jdporter (Paladin) on Dec 09, 2013 at 04:05 UTC

    I concur.

    TIMOTIMO wrote:

    ... and then sorts the original list based on the corresponding result list. In perl5, this was known as the 'schwartzian transformation'.
    That is a completely inaccurate characterization of the technique known as the ST. Yes, that's one thing that could be done with the ST, but the ST itself was far more general, and by definition must be a functional pipeline of the form map-sort-map.
    But there are also other — better — ways of "sorting an original list based on the corresponding result list." The brilliance of the ST is its conciseness, not its speed.

    I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
Re^2: sort +*, @array
by raiph (Deacon) on Dec 09, 2013 at 12:16 UTC
    I think "akin to ST" is reasonable.

    It's not the decorate-sort-undecorate of a by-the-book ST, but it's a direct equivalent which retains the ST's generality and efficiency and substantially improves on its elegance.

    To understand how the P6 design retains full ST capability, follow my attempt to P6ify your example thru two versions, the first not ST equivalent, the second equivalent:

    enum days <mo tu we th fr sa su>; enum months <jan feb mar apr may jun jul aug sep oct nov dec>; my $noon = DateTime.new(now) .truncated-to(day) .delta(12, hours); my @dates = $noon, *.delta(1, day), ... *; my @ordered = sort { ~days($^a.day-of-week - 1) cmp ~days($^b.day-of-week - 1) || ~months($^b.month - 1) cmp ~months($^a.month - 1) } ], @dates[^365];

    Some may quibble with the jump from the +* construct to a { ... } closure. But +* in term position is just sugar for a (one arg) closure (which as an arg to sort is assumed to be a "key extractor" closure).

    Some may quibble with the jump from a one arg "key extractor" closure to a two arg P5 style "comparator" closure. But P6 uses the one arg closure to do the same thing for both args ($a and $b in P5) in an automatically constructed comparator closure, and assumes use of cmp for comparison. So, no need for an explicit two arg "comparator" closure unless you really want one.

    Update I had intended that folk would read this comment as a whole, including what comes next, but I think some stopped at the above. The above works in current Rakudo, reads pretty cleanly, and is fully general functionally, but is not ST equivalent in at least the sense that it doesn't cache the keys. The following reads cleanly, does cache the keys, and is fully general -- but does not work in current Rakudo.

    enum days <<:mo(1) tu we th fr sa su>>; enum months <<:jan(1) feb mar apr may jun jul aug sep oct nov dec>>; my $noon = DateTime.new(now).truncated-to(day).delta(12, hours); my @dates = $noon, *.delta(1, day), ... *; my @ordered = sort [ { ~days(.day-of-week) }, { ~months(.month) } is descending ], @dates[^365];

    Update Let's add some commentary to try make the ST equivalency pop...

    Those two closures ({ ~days(.day-of-week) }, { ~months(.month) }) are key extractor closures. They correspond to the two calls in the P5 original:

    substr(scalar localtime($_),0,3), substr(scalar localtime($_),+5,3)

    Just as one can have arbitrary before maps with P5 ST, the P6 sort builtin design supports any number of arbitrary key extractor closures. P6 then automatically generates two comparator closures, and runs the first comparison to see if it sorts between a given pair of items, and if it doesn't, runs the next comparison. This corresponds to the P5:

    $a->[1] cmp $b->[1] || $b->[2] cmp $a->[2]

    (The descending aspect of the second cmp expression in the P5 comparator closure is covered by the is descending trait on the second closure in the P6 code.)

      but it's a direct equivalent

      By that logic, every sort could be called a ST. That just doesn't make sense. Use the term as it is defined and well known: decorate-sort-undecorate!

      retains the ST's generality

      I don't see how it does that at all. Unless it can do decorate-sort-undecorate, it falls very far short of the ST's generality.

      And it's not just about the "decorate" step, which your "key extractor" closure is roughly equivalent of. Because the ST has an explicit sort block (normally, unless it's the GRT variant :-)), it allows to execute arbitrarily complex Perl code in the comparison. Where does one do that in this Perl 6 "equivalent"?

      I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
        I'm not saying that the design of the P6 builtin is ST, just that it is functionally equivalent, and even more concise.

        And it's not just about the "decorate" step, which your "key extractor" closure is roughly equivalent of.

        One critical point: while a "key extractor" closure is indeed roughly equivalent to the decorate step in terms of the role it's playing, it's multiple key extractor closures that is basically fully equivalent to the before map.

        Because the ST has an explicit sort block (normally, unless it's the GRT variant :-)), it allows to execute arbitrarily complex Perl code in the comparison. Where does one do that in this Perl 6 "equivalent"?

        You just specify a comparator closure (or multiple, if you want).

        (P6 can tell the difference due to a closure's number of args. If it has one, it's a key extractor closure, if it has two it's a comparator closure.)

        For lots more examples which are still correct modulo a few minor syntax shifts, see "The Sort Problem: a definitive ruling" from 2004.

        Which got me to focus on the Pair variant which maybe helps clarify the connection for you:

        sort { #`( key extractor closure) } => { #`( comparator closure) }, { #`( key extractor closure) } => { #`( comparator closure) }, ... @array

      That's not an ST, it's at best an Orcish Maneuver. (Or simply shorthand for {$a<=>$b}.)

      Some may quibble ...

      And some may simply stop reading misinformation...


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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.
        It's not an Orcish Maneuver.

        The original example +* (reads "numeric context Whatever") is syntactic sugar for the one arg closure {+*} which is in turn treated by the P6 sort builtin as a key extractor and results in use of the comparator closure {$a<=>$b}.

        I've realized I didn't make it clear that my response to your challenge contained two parts and you needed to read both to see the ST equivalence. I suspect you didn't read both. I've updated it to try make things clearer.