The following arose out of a discussion on #perl6. Junctions are new
and different from anything I have encountered, but I cant get rid of
the feeling that there needs to be some more flexibility in their use
to make them a common programming tool.
Background: Imagine a hand of cards. Cards may be Ace, Two, Three. Ace
having either the values 1 or 11, depending on context, the other
cards their face value. Sums of a hand over 21 are invalid.
Hands with multiple junctions become interesting, eg.,
p: Ace, Two, Ace
d: Ace, Three, Ace
Given that Ace has a value of 1 or 11 depending on context, it would
seem natural to use a junction. Hence the two hands can be expressed as:
@p = 1|11, 2, 1|11;
@d = 1|11, 3, 1|11;
If we use [+] to add these, we get
$p = [+] @p; say $p.perl; # any(any(4,14),any(14,24))
$d = [+] @d; say $d.perl; #any(any(5,15),any(15,25))
Since the values of 24 & 25 are greater than 21, they must be
eliminated from consideration.
What we want is for hand @d to beat hand @p because 15 > 14
On #perl6, rouso, masak and moritz_ explained that I am incorrectly
thinking about junctions as sets and that for this task I should be
using another perl idiom, namely lists. Something like:
moritz_ rakudo: ([1,11], 3, [1,11]).reduce({@($^a) X+ @($^b)})
p6eval rakudo bb22e0: RESULT«[5, 15, 15, 25]»
Then the out-of-limit values (in the above case 25) can be stripped
off using grep, viz.,
# here we have ([1,11],3,[1,11]) instead of (1|11, 3, 1|11)
my @dlist = grep { $_ < 21 } ([1,11], 3, [1,11]).reduce({@($^a) X+
@($^b)});
Then the two lists (do the same for @p) can be compared by a junction
comparison of the form
if any(@plist) > all(@dlist) { say 'p wins' };
The problem is not just that [+] @p produces a junction with undesired
(>21) eigenstates, but that the [+] @d produces a junction of the form
any(any(5,15),any(15,25)) which should collapse to any(5,15,25)
whereas we want a junction of the form
all(5,15,25)
After the #perl6 conversation, I thought some more. A junction is a
neat way of expressing the hand, but the junction needs to be
converted to a list to do some processing, and then the lists are
compared using junctions.
I think (I might be wrong) that the conversion from a junction to a
list is specified by the .eigenstates method, but it doesn't seem to
completely flatten a junction yet - it produces the
any(any(4,14),any(14,24)) output shown above.
So my questions to the language list are:
a) Am I trying to fit a square peg in a round hole by applying
junctions to this sort of problem? If so, would it be possible to
explain what the limits are to the junction approach, or another way
of expressing this question: what sort of problems should junctions be
applied to?
b) Why would it be "wrong" to have a method for eliminating
eigenstates from a junction? (The answer to this might naturally arise
out of the answer to a). However, ...
In a wider context, I would conjecture that some algorithms to which
junctions could be applied would be optimised if some states could be
eliminated, a bit like tree-pruning optimisations that eliminate paths
which can never produce a correct answer. Consequently, providing a
filtering method would increase the usefulness of the junction as a
programming tool. Perhaps
$new-junction = $old-junction.grep({ $_ <= 21 }); # not sure if the
parens are needed here
c) On junction algebra, am I wrong or is always true that a junction
of the form
any('x','y','z', any('foo','bar'), 1, 2, 3) should collapse to
any('x','y','z','foo','bar',1,2,3)
In other words, if an 'any' junction is contained in an outer 'any',
the inner 'any' can be factored out?
This would eliminate the nested junctions produced by .eigenstates
d) Am I right in thinking this is also true for nested 'all'
junctions? viz.
all(1,2,3,all('foo', 'bar')) collapses to all(1,2,3,'foo','bar')
e) Conjecture: This true of all junction types, eg.,
junc(..., junc(...)) == junc(..., ...)
f) Would it be possible to have a means to coerce an 'any' junction
into an 'all' junction or vice versa? eg.
my $old-junction = 1|2|3; my $new-junction = all{$old-junction}; say
$old-junction.perl
# all(1,2,3)
Using () creates a new junction all(any(1,2,3))
{} are undefined for junctions.
If my suggestions prove acceptable, then for my problem I would have:
# @p & @d get defined as arrays of junctions, eg.
my @p=1|11,2,1|11;
my @d=1|11,3,1|11;
#later
my $p = ([+] @p).grep { $_ < 21 };
my $d = ([+] @d).grep { $_ < 21 };
if $p > all{$d} { say 'p wins' } else { say 'd wins' };