Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl 6 type inference

Given:

sub abc(Int $n) { say $n }

If we pass a variable typed as Str to abc we get a compile-time error:

my Str $s = "123";   abc $s;

If we pass an untyped variable that holds a string, we get a runtime error:

my $s = "123";   abc $s;

C++ supports an auto keyword which allows for type inference.

Is it possible to define something like auto in Perl 6 such that:

auto $s = "123";

would result in $s being typed as Str?

I.e. then we could do the following:

auto $s = "123";   abc $s;

And get a compile-time error.

like image 514
dharmatech Avatar asked May 24 '18 18:05

dharmatech


3 Answers

What you are looking for is probably what we call allomorphs in Perl6, types that can behave differently depending on the context. For the particular case you have posted, there's the IntStr allomorph:

sub abc(Int $n) { say $n }
my IntStr $s = <123>;
abc $s; # prints 123

(Please note that it needs the quote-words <> instead of the usual ""). Allomorphs, in general, are subclassses of the classes they can be typecasted into; IntStr subclasses Int and Str. This can be done in general for any types you want to auto, as long as they are mutually convertible.

Another option, if you already know what you are going to get and what it is being turn into, is to use coercion:

sub bcd(Int(Str) $n) { say $n }
my $t = "123";
bcd $t; # prints 123

In this case, the string will be coerced to an Int in the Capture before being used by the subroutine body.

Finally, you can use the number contextualizer, as long as you use when the variable is effectively going to be used.

sub efg($n) { say +$n }
my Int $u = 123;
my Str $v = "123";
efg $u;
efg $v;

+ puts a variable in a numeric context, automatically converting it to a number. You can even turn that into a signature constraint if you want to restrict it to either Int or Str

sub xyz($n where $_ ~~ Int | Str ) { say +$n }
xyz $u;
xyz $v;
xyz $t;
xyz $s;

(It's using the variables defined above) Here it will work no matter if the variable does not have a type assigned (like $t, or has been defined as IntStr, Int or Str). As long as it can be smartmatched to Int or Str, it will be fed into the sub body and turned into a number via contextualization.

Full program is here, just in case you want to download and check it.

like image 140
jjmerelo Avatar answered Nov 13 '22 07:11

jjmerelo


Is it possible to define something like auto in Perl 6

I think it is, sort of. But I'm going to have to translate your question into three different ones to provide a more useful answer.

For my answers to the first two questions below, please reference a reddit comment I wrote about this. My comment was in four parts, separated by horizontal rules. The first and last parts are relevant to your question.

Is it possible to modify the Perl 6 language?

Yes.

You can more or less arbitrarily modify the Perl 6 language on the fly from userland code.

Quoting a bullet point from the first part of the comment I linked above:

  • Internal slang DSLs built using grammars, like an external DSL, but mixed in with the standard Perl 6 grammar via the slang mechanism. These DSLs must be written to have at least some basic coordination with the standard Perl 6 grammar. Code written in such DSLs appears inline, indistinguishable from regular code. Relevant slides.

Quoting a bit of the last part I wrote:

While slangs can be implemented ... they are not officially supported ... and are not as sugary as they need to be.

Is it possible to write compile-time macros that communicate with the compiler?

Yes.

Unfortunately you can't yet define statement macros, which is what you'd need for a new type of variable declaration. Quoting the last section in the comment I linked above:

"The intended design options for situations where you want an internal DSL but it's too syntactically in conflict with standard Perl 6 to just use user defined routines and operators are ... Write an is parsed macro [or] Write a slang. Either of these can, in theory, parse any syntax you want. But is parsed macros haven't landed and look like they're at least a year or three away -- they're still just a design concept being discussed in 007."

Is it possible to get new ideas into Perl 6?

Yes.

Just implement your idea and lobby for its inclusion. Possibly start with a slang. Possibly just directly hack on the entire compiler.

I'm being serious about that last point.

The Rakudo Perl 6 compiler is of course open source.

Much more importantly, it's mostly written in Perl 6. (And most of what isn't Perl 6 is nqp which is basically a subset of full Perl 6.)

Conclusion

If you can write some basic Perl 6 code; are willing to ask loads of questions on the freenode IRC channel #perl6-dev; and are patient; then you should be able to implement just about any idea in Perl 6 and your auto idea seems relatively simple.

(Where by "relatively" I'm imagining a knowledgeable core dev might be able to do a proof of concept in a few hours assuming I've correctly understood the problems they'd face. And one day, when slangs and/or macros are more polished perhaps it would take about an hour.)

like image 32
raiph Avatar answered Nov 13 '22 07:11

raiph


I just want to mention Proxies. These work at the container level and only at run-time. But give some ability to control or track what's going into a variable.

sub auto($v?) is rw {
    my $val = $v;
    Proxy.new(
        FETCH => -> $, { $val },
        STORE => -> $, $new-val {
            die "You canna change type from {$val.WHAT.^name} to {$new-val.WHAT.^name}"
                unless $new-val.WHAT ~~ $val.WHAT;
            $val = $new-val;
        }
    )
}

my $i := auto(11);
$i = 69;
say $i;
$i = 'blah'; # Boom

Proxys can be used to implement something like the auto types, but only at run-time and only at the container level. They're also not quite as water-tight, as the container associated with a variable can change. For example, using the bind := operator

$i := 'he he'; # changed container
like image 34
dwarring Avatar answered Nov 13 '22 07:11

dwarring