Reductions, junctions, hashslices, and cribbage scoring

48 views
Skip to first unread message

Rob Kinyon

unread,
May 25, 2005, 1:29:55 PM5/25/05
to Perl6 Language List
(This post references the discussion at
http://www.perlmonks.org/?node_id=458728, particularly dragonchild's
response at the bottom.)

For those who don't know, cribbage is a game where each player has
access to 4 cards, plus a community card. Various card combinations
score points. The one in question is when cards add up to 15. If you
have a group of cards that add up to 15, you receive 2 points. This is
for every group, so if you have a ten and 2 fives, you get 4 points.
Two tens and two fives is 8 points. Face cards are worth 10 and aces
are 1, for these purposes.

I proposed the following:

# Fifteens
$score += 2 * all( 15 == [+]@hand{ any( 0 .. 4 ) } );

* Is this syntax legal?
* Does it do what I want it to do?
* Is there another way?

Thanks,
Rob

Rob Kinyon

unread,
May 26, 2005, 1:37:17 PM5/26/05
to Perl6 Language List
> Assuming you write the subset coroutine above, how about
>
> $score +=
> ( subsets(0..4) ==> map { 2 * (15 == [+] @hand{@$_}) } ==> [+] )

Working on it last night and this morning, I ended up with the
following, very similar rewrite.

sub gen_idx_powerset (Int $size is copy) returns Array {
my @c = ([]);
for 0 .. $size-1 -> $i {
push @c, (map { [@$_, $i] }, @c);
}
return @c;
}

# Fifteens
$score += 2 * grep {
15 == [+]( @hand[@$_]>>.<val> )
}, gen_idx_powerset( +@hand );

(Also available at http://www.perlmonks.org/?node_id=460666)

(I had an error in my original posting. @hand is an AoH. My original
should have hypered to .<val> like my second one does.)

Question: Is it possible using hypers and the like to replace the
gen_idx_powerset() sub with an inline expression? I'm not worried
about maintainability - I wanna see what the new ops can do!

Thanks,
Rob

John Williams

unread,
May 26, 2005, 1:03:15 PM5/26/05
to Rob Kinyon, Perl6 Language List

I think so.

> * Does it do what I want it to do?

Definitely not. It looks like you are thinking of junctions in terms of
arrays, instead of scalar quantum superpositions.

any( 0 .. 4 )

This returns a scalar junction of the five values (0,1,2,3,4).
What you want is clearly all possible subsets of 0..4. You probably
should write a coroutine to generate a lazy list of them.

@hand{ $junction }

returns a scalar junction of the five cards in the hand. Junctions
auto-thread through operators, including postcircumfixes.

[+] $junction

returns $junction, since [+] $scalar == $scalar. The individual values
auto-thread through.

15 == $junction

This returns a junction of booleans. Knowing the possible values of
@hand, all of them are false.

all( $junction )

I'm not real good with nested junctions...

2 * $junction

This returns another junction, with all elements doubled. (still zeros)
You obviously want 2 * <junction>.elems, but I'm not sure if junctions
support that method.

$score += $junction

Again this will make $score a junction of values. It will not add each of
the junction values to $score. You probably want something like
C< $score >>+=<< $junction.values > but that is another indication
that you should be using arrays instead of junctions. And I'm not sure
about the object interface to junctions anyway.

> * Is there another way?

Assuming you write the subset coroutine above, how about

$score +=
( subsets(0..4) ==> map { 2 * (15 == [+] @hand{@$_}) } ==> [+] )


~ John Williams


Patrick R. Michaud

unread,
May 26, 2005, 2:01:22 PM5/26/05
to John Williams, Rob Kinyon, Perl6 Language List
On Thu, May 26, 2005 at 11:03:15AM -0600, John Williams wrote:
> > I proposed the following:
> >
> > # Fifteens
> > $score += 2 * all( 15 == [+]@hand{ any( 0 .. 4 ) } );
> >
> > * Is this syntax legal?
>
> I think so.
>
> > * Does it do what I want it to do?
>
> Definitely not.

First, apologies in advance for what I'm about to write: I'm going
to express some thoughts/ideas below and then pretty much leave it
to others to decide what (if anything) should be done with it.

The continuing exchanges regarding junctions, and the ongoing tendency
by newcomers to think of them and try to use them as sets, makes
me feel that it might be worthwhile to define and publish a standard
C<Set> class and operations sooner rather than later in Perl 6
development. This might reduce the tendency to confuse junctions
with sets, by providing something that is more clearly a "set" and
that has operations more closely aligned with what one is expecting.
From a "marketing" perspective, it could reduce the initial frustration
I suspect many people feel when they discover that junctions don't do
the set-type things they initially thought they would, by providing
something that does.

It becomes natural to ask if C<Set> should be part of the Perl 6 "core";
I think that's a distinction and distraction not worrying about at this
point. Clearly many people are trying to treat junctions as sets,
perhaps because there's no well-understood alternative for it.
Writing an alternative, even on a provisional basis, might be really
helpful to people.

Returning to the apology -- I recognize this is a "@we ought to do X"
post where $Pm ~~ none(@we), but given that there are a lot of people
who seem to like the notion of sets in Perl 6, I'm suggestion that
anyone who wanted to take a crack at drafting a proposal or implementation
would likely get lots of helpful feedback, suggestions, and contributions
from people who are looking to use them.

Pm

Sam Vilain

unread,
May 27, 2005, 12:55:32 AM5/27/05
to Patrick R. Michaud, John Williams, Rob Kinyon, Perl6 Language List
Patrick R. Michaud wrote:
> The continuing exchanges regarding junctions, and the ongoing tendency
> by newcomers to think of them and try to use them as sets, makes
> me feel that it might be worthwhile to define and publish a standard
> C<Set> class and operations sooner rather than later in Perl 6

I agree. See pugs/ext/Set.

It presents a set-like interface to Junctions.

eg,

use Set;

my $low = set( 0..4 );
my $odd = set( (0..4).map:{ $_ * 2 + 1 } );

say ($low ∩ $odd).members.join(","); # 1,3
say ($low ∪ $odd).members.join(","); # 0,1,2,3,4,5,7,9

# difference - not this is not a backslash, it's U+2216
say ($low ∖ $odd).members.join(","); # 0,2,4
say ($odd ∖ $low).members.join(","); # 5,7,9

# symmetric difference - union of the above
say ($low % $odd).members.join(","); # 0,2,4,5,7,9

# test for membership
say $low ∋ 4; # true
say $low ∌ 5; # true
say $odd ∋ 4; # false
say $odd ∌ 5; # false

# set relations
say ( $low ∪ $odd ) ⊇ $low; # true

Well, actually the above doesn't work yet. But there are ASCII versions
and english methods for those that like coding something that actually
works today ;).

Here's a directed graph traversal that handle cycles correctly; this is
largely why I'd like to see a common Role to all containers... so that
.values can be expected to DTRT. OTOH, maybe Maps with object keys would
"miss out" in this algorithm so another method name is more appropriate.

use Set;
my @stack = ($root);
my $seen = set(@stack);

while (my $item = shift @stack) {
# do something with $item

if $item.can("values") {
push @stack, $item.values.grep:{ $seen.insert($_) };
}
}

Caveats for the above probably abound, but you get the picture.

Note that the Set::Object module for Perl 5 is useful for the same thing
(assumes that $root is a ref):

use Set::Object qw(set);
use Scalar::Util qw(reftype blessed);
use Perl6::Junction qw(any);
my @stack = ($root);
my $seen = set(@stack);

while (my $item = shift @stack) {
# do something with $item

if (blessed $item and $item->can("members")) {
push @stack, grep { ref $_ && $seen->insert($_) } $item->members;
}
if (reftype $item eq "HASH") {
push @stack, grep { ref $_ && $seen->insert($_) } values %$item;
}
elsif (reftype $item eq "ARRAY") {
push @stack, grep { ref $_ && $seen->insert($_) } @$item;
}
elsif (reftype $item eq any(qw(REF SCALAR)) ) {
push @stack, $$item if $seen->insert($$item);
}
}

As you can see, this sort of thing ends up an anti-design pattern.

Sam.

Clement Cherlin

unread,
May 27, 2005, 1:07:05 AM5/27/05
to
In article <20050526180...@pmichaud.com>, pmic...@pobox.com
(Patrick R. Michaud) wrote:

> It becomes natural to ask if C<Set> should be part of the Perl 6 "core";
> I think that's a distinction and distraction not worrying about at this
> point. Clearly many people are trying to treat junctions as sets,
> perhaps because there's no well-understood alternative for it.
> Writing an alternative, even on a provisional basis, might be really
> helpful to people.

I think we should put Sets in the core and move Junctions out to a module.
Sets have well-understood semantics and operations. Junctions are obscure
and confusing. I have yet to see a compelling case for them being useful
outside the limited scope of boolean expressions.

The whole Junction concept strikes me as being an attempt to muddle data
with the operations we wish to carry out on that data. Sets do not have
that problem.

Michele Dondi

unread,
May 27, 2005, 5:00:57 AM5/27/05
to Patrick R. Michaud, John Williams, Rob Kinyon, Perl6 Language List
On Thu, 26 May 2005, Patrick R. Michaud wrote:

> The continuing exchanges regarding junctions, and the ongoing tendency
> by newcomers to think of them and try to use them as sets, makes
> me feel that it might be worthwhile to define and publish a standard
> C<Set> class and operations sooner rather than later in Perl 6
> development. This might reduce the tendency to confuse junctions

I fully second that. You can search the archives for my own thoughts on
the subject.


Michele
--
you'll see that it shouldn't be so. AND, the writting as usuall is
fantastic incompetent. To illustrate, i quote:
- Xah Lee trolling in clpmisc,
"perl bug File::Basename and Perl's nature"

Reply all
Reply to author
Forward
0 new messages