Hi Perl 6 people.

I've been looking closely at the definition of the Range class in S02 and the current Rakudo implementation, and I have some comments...


It seems that there are two intended uses for this class:
Range       A pair of Ordered endpoints
Lets call the above the "interval definition".
The |..| operator now constructs a |Range| object rather than merely functioning as an operator. Both sides are in item context. Semantically, the |Range| acts like a list of its values to the extent possible, but does so lazily, unlike Perl 5's eager range operator.
And this one the "list definition".


It seems fair enough to demand that a class supports both the concept of being able to tell whether some value is between two endpoints (even supporting open ranges) as well as being a lazy list in disguise, but this concept only works on countable domains.

The most common example is 1 .. 100, which represents both an object that can tell whether some other Integer is between 1 and 100 (inclusive) as well as the list of numbers from 1 to 100.

But there are problems if you try extending it to other data types that model over-countable things, such as real numbers.

The Range 1.0001 .. 2.15 makes sense as an interval definition, but there can hardly be a useful list definition without defining a step size, at least, making it possible to use step sizes less than one.

This issue also surfaces when working with strings. As far as I can see, Rakudo has some other comparison operation, which means that Ranges using String endpoints are not dwimmy in the sense I'd expect:

say @("a" .. "ax").perl; # expands to a .. z, aa .. ax
say @("aa" .. "b").perl; # expands to the empty list

As far as I can see, the ordering is like so:

sub { $^a.chars cmp $^b.chars || $^a cmp $^b }

The code below shows that Rakudo does not currently use lexicographical comparison, which may be surprising.

say 'aaa' cmp 'aa';
say 'aaa' cmp 'ba';
say 'aaa' ~~ 'aa' .. 'ba';

The output is:
1
-1
0

The last 0 should be 1 if using normal lexicographical ordering, just like cmp does.

It is necessary to consider the data types that we want to use as interval endpoints and carry out some sort of analysis of their domains. The basic requirements are:

For the interval definition: there must be an obvious ordering relation, so we can do $a cmp $b on any $a and $b of the given data type.

For the list definition: for any value $a of the given datatype, it must be possible to come up with some $b, where no $c exists so $a < $c < $b.

Now for a short analysis of the different data types used as end points:

Integers - both interval and list definitions are ok.

Str - using lexicographical comparison permits only the interval definition. Using the different comparison operator above permits both, but results in counter-intuitive interval definition.

Num - using numerical comparison permits only the interval definition. It should be easy to come up with a way to specify step sizes to support list definition.

Complex - neither definitions are possible.

I am unsure about how this can be solved, apart from extracting the interval definition to a super class to Range (we could call it an Interval). The backside is that the class returned by the .. operator depends on the operands:

Int .. Int -> Range
Str .. Str -> Interval
Complex .. Complex -> undef, exception or some other bad thing.
DataTypeA .. DataTypeB -> undef, exception or some other bad thing.

The most elegant solution would be if the data types themselves indicated their capabilities. So if the given class has a cmp method working on the same data type, the .. can construct an Interval. If the given class has a next method (my name for a method returning the next value), the .. can even construct a Range. If you want to construct an Interval using non-countable things, you should then be able to provide your own next replacement. Maybe like so:

my $range = 1.14 .. 1.82 :by {* + 0.01};

Another option is to provide a completely different operator for constructing Intervals.

Darren Duncan brought this up before. See http://osdir.com/ml/perl6-language/2009-02/msg00422.html

Regards,

Michael Zedeler.



Reply via email to