Doing math with Perl 6

Different mathematical paradigms and how they are implemented in this language

Sets

Perl 6 includes the Set data type, as well as support for most set operations. Union and intersection are not only native operations, they use their natural symbols, ∩ and ∪. For instance, this code would check the fundamental laws of the arithmetic of sets for a limited number of sets:

my @arbitrary-numbers = ^100;
my \U = @arbitrary-numbers.Set;
 
my @sets;
 
@sets.push: Set.new@arbitrary-numbers.pick@arbitrary-numbers.elems.rand)) for @arbitrary-numbers;
 
my (@union@intersection);
 
for @sets -> $set {
    @union.push: $set  $set === $set;
    @intersection.push: $set  $set === $set;
}
 
say "Idempotent union is "so @union.all;
# OUTPUT: «Idempotent union is True» 
say "Idempotent intersection is "so @intersection.all;
# OUTPUT: «Idempotent intersection is True» 
my (@universe@empty-set@id-universe@id-empty);
 
for @sets -> \A {
    @universe.push: A  U === U;
    @id-universe.push: A  U === A;
    @empty-set.push: A  ∅ === ∅;
    @id-empty.push: A  ∅ === A;
}
 
say "Universe dominates "so @universe.all;    # OUTPUT: «Universe dominates True» 
say "Empty set dominates "so @empty-set.all;  # OUTPUT: «Empty set dominates True» 
 
say "Identity with U "so @id-universe.all;    # OUTPUT: «Identity with U True» 
say "Identity with ∅ "so @id-empty.all;       # OUTPUT: «Identity with ∅ True» 

In this code, which uses the empty set which is already defined by Perl 6, not only do we check if the equalities in the algebra of sets hold, we also use, via sigilless variables and the Unicode form of the set operators, expressions that are as close as possible to the original form; A ∪ U === U, for example, except for the use of the value identity operator <===> is very close to the actual mathematical expression in the Wikipedia entry.

We can even test De Morgan's law, as in the code below:

my @alphabet = 'a'..'z';
my \U = @alphabet.Set;
sub postfix:<>(Set $a{ U  $a }
my @sets;
@sets.push: Set.new@alphabet.pick@alphabet.elems.rand)) for @alphabet;
my ($de-Morgan1,$de-Morgan2= (True,True);
for @sets X @sets -> (\A, \B){
    $de-Morgan1 &&= (A  B)⁻  === A⁻  B⁻;
    $de-Morgan2 &&= (A  B)⁻  === A⁻  B⁻;
}
say "1st De Morgan is "$de-Morgan1;
say "2nd De Morgan is "$de-Morgan2;

We declare as the complement operation, which computes the symmetrical difference ⊖ between the Universal set U and our set. Once that is declared, it is relatively easy to express operations such as the complementary of the union of A and B, (A ∪ B)⁻, with a notation that is very close to the original mathematical notation.

Arithmetic

Perl 6 can do arithmetic using different data types. Num, Rat and Complex can all operate as a field under the operations of addition, subtraction, multiplication and division. The equivalent mathematical fields are:

Perl 6 class Field
Rat
Num
Complex

The Ints, although technically corresponding to Z, is not really a mathematical field since they are not closed under the four arithmetical operations, and integers do not satisfy the identity axiom. However, if the integer division div is used, their operations will always yield other integers; if / is used, however, in general the result will be a Rat.

Besides, Int can do infinite-precision arithmetic (or at least infinite as memory allows; Numeric overflow can still occur), without falling back to Num if the number is too big:

my @powers = 22 ** * ... Infsay @powers[4].chars# OUTPUT: «19729␤» 

Also strictly speaking, the Rational class that behaves like a mathematical field is FatRat. For efficiency reasons, operating with Rats will fall back to Num when the numbers are big enough or when there is a big difference between numerator and denominator. FatRat can work with arbitrary precision, the same as the default Int class.

Some modules in the ecosystem can work with additional data types mathematically:

Numbers are duck-typed automatically to the numeric class they actually represent:

.^name.say for (4, ⅗, 1e-93+.1i); # OUTPUT: «Int␤Rat␤Num␤Complex␤» 

Which makes also arithmetic operations the most adequate for the particular type

say .33-.22-.11 == 0# OUTPUT: «True␤» 

In this case, all numbers are interpreted as Rats, which makes the operation exact. In general, most languages would interpret them as floating point numbers,

say .33.Num -.22.Num - .11.Num# OUTPUT: «1.3877787807814457e-17␤» 

For cases such as this, Perl 6 also includes an approximately equal operator,

say .33.Num -.22.Num - .11.Num  0# OUTPUT: «True␤» 

Sequences

A sequence is an enumerated collection of objects in which repetitions are allowed, and also a first-class data type in Perl 6 called Seq. Seq is able to represent infinite sequences, like the natural numbers:

my \𝕟 = 1,2 … ∞;
say 𝕟[3];# OUTPUT: «4␤» 

Infinite sequences use ∞, Inf or * (Whatever) as terminator. is the list generator, which in fact can understand arithmetic and geometric progression sequences as long as you insert the first numbers:

say 1,5,9 … * > 100;
# OUTPUT: «(1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77 81 85 89 93 97 101)␤» 
say 1,3,9 … * > 337# OUTPUT: «(1 3 9 27 81 243 729)␤» 

The first sequence will be terminated when the generated number is bigger than 100; the second sequence, which is a geometric progression, when it is bigger than 337.

The fact that an arbitrary generator can be used makes easy to generate sequences such as Fibonacci's:

say 1,1* + * … * > 50;#  OUTPUT: «(1 1 2 3 5 8 13 21 34 55)␤» 

We can, in fact, compute the approximation to the golden ratio this way:

my @phis = (2.FatRat1 + 1 / * ... *);
my @otherphi = (1 - @phis[200], 1 + 1 / * ... *);
say @otherphi[^10|(2030 ... 100)];# OUTPUT: 
# «((-0.61803398874989484820458683436563811772030918 
# -0.61803398874989484820458683436563811772030918 
# -0.61803398874989484820458683436563811772030918 
# -0.61803398874989484820458683436563811772030918 
# -0.61803398874989484820458683436563811772030918 
# -0.618033…» 

The Math::Sequences module includes many mathematical sequences, already defined for you. It defines many sequences from the encyclopedia, some of them with their original name, such as ℤ or ℝ.

Some set operators also operate on sequences, and they can be used to find out if an object is part of it:

say 876  (7,14 … * > 1000) ; # OUTPUT: «False␤» 

In this particular case, we can find out if 876 is a multiple of 7 straight away, but the same principle holds for other sequences using complicated generators. And we can use set inclusion operators too:

say (55,89).Set  (1,1* + * … * > 200); # OUTPUT: «True␤» 

although it does not take into account if it is effectively a subsequence, just the presence of the two elements here; Sets have no order, and even if you don't explicitly cast the subsequence into a Set or explicitly cast it into a Seq it will be coerced into such for the application of the inclusion operator.

Mathematical constants

Perl 6 includes already a set of mathematical constants as part of the core.

say π# OUTPUT: «3.141592653589793» 
say τ# Equivalent to 2π; OUTPUT: «6.283185307179586» 
say 𝑒; # OUTPUT: «2.718281828459045␤» 

which are available also by their Latin name, e, pi and tau, with the same value (although 𝑒 is not available outside the MoarVM).

The Math::Constants module includes an additional series of physical and mathematical constants such as the previously mentioned golden ratio φ or the Planck's constant ℎ.

Since Perl 6 allows for definition of variables that use Unicode graphemes, and also variable and constant names without any kind of sigil, it is considered a good practice to use the actual mathematical name of concepts to denominate them wherever possible.