Where can I learn about perl6 Type variables (::T) - raku

I need to use perl6 type variables. It seems that the definitive manual is here http://www.jnthn.net/papers/2008-yapc-eu-perl6types.pdf, which is concise and v. useful in so far as it goes.
Is there anything more comprehensive or authoritative that I can be pointed to?

What you're referring to is called "type capture" in perl6, here's two pages about them:
Type Captures in function/method signatures: https://docs.perl6.org/type/Signature#index-entry-Type_Capture_%28signature%29
Type Captures in Roles: https://docs.perl6.org/language/typesystem#index-entry-Type_Capture_%28role%29
Hope that helps!

The way I like to think of it is that Int is really short for ::Int.
So most of the time that you are talking about a type, you can add the :: to the front of it.
Indeed if you have a string and you want to use it to get the type with the same short name you use ::(…)
my $type-name = 'Int';
say 42 ~~ ::($type-name); # True
The thing is that using a type in a signature is already used to indicate that the parameter is of that type.
-> Int $_ {…}
Any unsigiled identifier in a signature is seen as the above, so the following throws an error if there isn't a foo type.
-> foo {…}
What you probably want in the situation above is for foo to be a sigiless variable. So you have to add a \ to the front. (Inside of the block you just use foo.)
-> \foo {…}
So if you wanted to add a feature where you capture the type, you have to do something different than just use an identifier. So obviously adding :: to the front was chosen.
-> ::foo { say foo }
If you call it with the number 42, it will print (Int).
You can combine these
-> Real ::Type \Value {…}
The above only accepts a real number (all numerics except Complex), aliases the type to Type, and aliases the number to Value
sub example ( Real ::Type \Value ) {
my Type $var = Value;
say Type;
say Value;
}
> example 42;
(Int)
42
> example ''
Type check failed in binding to parameter 'Value'; expected Real but got Str ("")
in block <unit> at <unknown file> line 1
> example 42e0
(Num)
42
This is also used in roles.
role Foo[ Real ::Type \Value ] {
has Type $.foo = Value; # constrained to the same type as Value
}
class Example does Foo[42] {}
say Example.new( :foo(128) ).foo; # 128
say Example.new().foo; # 42
say Example.new( :foo(1e0) ); # Type check error
You can of course leave off any part that you don't need.
role Foo[::Type] {…}

Related

What is right part in "query : SelectionSet Response RootQuery" type annotations?

I try to understand this line:
query : SelectionSet Response RootQuery
I understand this is a "Type Annotations" syntax, but I don't find documentation example or explanation about multiple "word" separated by whitespace.
I see these examples:
answer : Int
factorial : Int -> Int
distance : { x : Float, y : Float } -> Float
add : number -> number -> number (ref)
I found anywhere query: Int Int Int syntax, neither in Elm Syntax nor in Beginning Elm nor in Elm FAQ.
Do SelectionSet, Response, RootQuery are
functions arguments?
multi value function results?
Best regards,
Stéphane
Same question on Elm Discourse
A response in How do I read the type of a SelectionSet?
SelectionSet is a type with two type variables. Here's the definition:
type SelectionSet decodesTo scope
= SelectionSet (List RawField) (Decoder decodesTo)
In a type declaration like this, any lowercase name after the type is a type variable, which can be filled in by any type (except for a few special constrained type variables, number, appendable, comparable, and compappend). A simpler example would be Maybe, where you can have a Maybe Int or a Maybe String. Similarly, Dict takes two type variables (for the key and value) so you can have Dict String String or Dict Int MyCustomType (the key type of a Dict does need to be comparable).
So, in your scenario, Response corresponds to decodesTo and RootQuery corresponds to scope. The SelectionSet has a Decoder that decodes to a Response value, and it also carries around this scope type variable, which isn't used directly in the data that it holds. It's used as a piece of information at the type level, so that you (and the library) know that calling map (which has the type (a -> b) -> SelectionSet a scope -> SelectionSet b scope) will preserve that scope value; that is, it prevents mixing scopes.
The above is mostly general function syntax for functional languages such as Haskell, Elm, etc.
For example:
add : Int -> Int -> Int
add x y = x + y
The first line says that is function of two integer arguments with an integer return value. The second line implements the specification given in the first. One calls this function as follows:
> add 2 3
5
Note this example:
> inc = add 1
> inc 2
3
Here add 1 is a "partially applied function." It has type Int -> Int. In many languages, add 1 would not make sense. But since functions are first-class things in Elm, add 1 makes sense: it is a function. Partial application is also called "currying."

`does` versus `but` operators when mixing in a Role into an object in Raku

If I have a Role R defined as:
role R { method answer { 42 } }
What is the difference (if any) between these two lines:
my $a = 'question' does R;
my $b = 'question' but R;
They appear very similar:
say $a.answer; # OUTPUT: «42»
say $b.answer; # OUTPUT: «42»
say $a.WHAT; # OUTPUT: «(Str+{R})»
say $b.WHAT; # OUTPUT: «(Str+{R})»
Is this a case of there being More Than One Way To Do It™, and these both mean the same thing? Or is there a subtle difference that I'm missing?
note:
I understand that does is both an operator and a trait and thus can be used when for compile-time mixins (e.g., class C does R {}) whereas but is only for runtime mixins. I also understand that but can be used with an object (e.g., my $c = 'question' but False) whereas does can only be used with a Role. I'm not asking about either of those differences; my only question is about whether there's a difference when both are used at runtime with a Role. I have read the documentation section on mixing in Role, but didn't see an answer.
Put simply:
does modifies an object in place (and should be used with caution with value types, see note below)
but returns a new object.
When created off of a literal, it's probably not as evident, but when used with another object, it's pretty clear I think:
role R { method answer { 42 } }
my $question = 'question';
my $but = $question but R;
my $does = $question does R;
say $question.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R})
say $does.WHAT;  # (Str+{R})
say $question.WHERE; # 129371492039210
say $but.WHERE; # 913912490323923
say $does.WHERE; # 129371492039210 <-- same as $question's
Notice I cheated a bit and swapped the order of does and but. If I had preserved the order you had, the does would modify $question in place, applying the role, meaning that but would clone $question (with its role) and apply the role (again!):
my $does = $question does R;
my $but = $question but R;
say $does.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R}+{R})
This is because does as an operator is conceptually akin to ++ or +=, that is, designed to be used in a standalone context, for instance
my $foo = …;
given $bar {
when 'a' { $foo does A }
when 'b' { $foo does B }
when 'c' { $foo does B }
}
Using but is conceptually closer to using $foo + 1 — mostly meaningless unless assigned to or passed to something else.
A warning for does and value types
If you use does on a value type (strings, numbers mainly), there is an extremely high likelihood that you will cause unintended side effects. This is because value types (which, e.g., strings are) are supposed to be immutable and substitutable for one other. Note the following:
role Fooish { }
my $foo = 'foo';
$foo does Fooish;
say 'foo'.WHAT; # (Str+{Fooish})
This is a substitution that's happening at compile time (so it won't affect, e.g, 'foobar'.substr(0,3), that happens at runtime), but can cause some truly weird effects if you toss them in a loop:
role Fooish { }
my #a;
#a.push('foo' does Fooish) for ^10;
say #a[0].WHAT; # (Str+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish}
+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish})
Applying multiple rolls takes longer and longer the more you do it, so if you change that to ^100000, be ready to wait a while. OTOH, doing but gives you nice constant time and doesn't pollute the literal. This behavior seems, AFAICT, to be perfectly valid, but definitely something that can catch you unexpectedly.

Parametrized types in Raku, how to use run time values as parameters

I'd like to create some parametrized types for Raku; basically, I'd like to create some different classes whose main difference would be the range of values of one of its attributes; for instance, classes represent types of building, I'd like to have different classes for buildings with 3 or any other number of floors.
So this is the best I could think of:
subset Two-Tops of UInt where * <=2;
subset Three-Tops of UInt where * <=3;
role Zipi[ ::Capper ] {
has Capper $.floor;
}
class Capped-at-three does Zipi[Three-Tops] {}
my $capped = Capped-at-three.new( floor => 2 );
say $capped.raku;
This is clearly unpractical as soon as you need to take care of many different numbers of floors (not here in Granada, where they have at most 10, I think, but well... ). The problem here is basically you need to have the information for subsets at compile time, so unless you use macros (still experimental), there's no way you can use any kind of variable. So can you think of a practical way of defining this kind of curried roles for any value of the parameter?
Actually, unlike I said in my previous you can use conditions in where clauses without problem, you just need to encase them in braces:
role Zipi[$condition] {
has $.floor is rw where {$_ ~~ $condition}
method foo($x) { $!floor = $x }
}
class A does Zipi[2 < * < 5] {
method bar($x) { $.floor = $x }
}
#my $a = A.new( floor => 10); # error
my $a = A.new( floor => 4); # OK
#$a.foo(10); # error
$a.foo(3); # OK
#$a.bar(0); # error
$a.bar(4); # OK
#$a.floor = 9; # error
$a.floor = 3; # OK
That should cover all of the assignment types
I have very limited MOP chops, and the following seems ugly, but it works, and might be a step in the right direction.
What I've done:
Dynamically constructed an array of 10,000 subsets via the MOP.
Time shifted their construction to compile time via BEGIN.
Used an appropriate element from the array to parameterize the role.
my #max-floors-checkers;
BEGIN {
#max-floors-checkers = do for ^10_000 -> \floors {
Metamodel::SubsetHOW.new_type:
refinee => UInt,
refinement => { $^floors <= floors }
}
}
role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
class Capped-at-three does BuildingCategory[ #max-floors-checkers[3] ] {}
my $capped3 = Capped-at-three.new( floors => 2 );
say $capped3.raku; # Capped-at-three.new(floors => 2
my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed
I tried using anonymous where clauses, but similarly to no avail, but I tracked down the issue: the where clause is apparently being ignored by the BUILD method . I'm not sure if it's because it has direct access (via $!floor) which bypasses the where clause, or if something else weird is going on (probably the latter, I general got Nil if I tried to use the paramaterized value in a where clause).
Nonetheless, this should work nicely, including giving a helpful error message:
role Zipi[$condition] {
has $.floor;
submethod BUILD(:$floor, |c) {
die "Invalid floor number."
unless $floor ~~ $condition;
$!floor = $floor;
}
}
You can see how it'd be easy to modify if you can assume floors are always 0 .. x, or x .. y and could provide an even more helpful error message.
A nanswer covering the case a reader knows Java but not Raku.
Collection<String> coll = new LinkedList<String>();
parametrized types for Raku
The linked Java example is:
The instantiation of a generic type with actual type arguments is called a parameterized type. Example (of a parameterized type):
Collection<String> coll = new LinkedList<String>();
A reasonable Raku analog is:
my Positional[Str] \coll = Array[Str].new;
The Positional type is a parameterizable role. A role specifies an interface and/or partial implementation of a type. I believe Raku's Positional is sufficiently analogous to Java's Collection that it serves for the purposes of this nanswer.
The Array type is a parameterizable class. It specifies a data structure that adheres to the Positional role. It isn't a linked list but it will suffice for the purposes of this nanswer.

A better way to introspect a capture

I want to test the type of the first object in a signature. The following shows some ways I have found that work. But why does a smart match on a Type (2nd of the 3 tests below) not work?
Is there a better way than stringifying and testing for the string equivalent of the Type?
(Below is the use case I am working on)
raku -e "sub a( |c ) { say so |c[0].WHAT.raku ~~ /'Rat'/, so |c[0].WHAT ~~ Rat, so |c[0].^name ~~ /'Rat'/ };a(3/2);a(2)"
TrueFalseTrue
FalseFalseFalse
# OUTPUT:
#TrueFalseTrue
#FalseFalseFalse
I am writing a proto sub handle, and most of the subs have similar signatures, eg. multi sub handle( Pod $node, MyObj $p, Int $level --> Str)
So most of the multi subs do different things depending on what is in $node. However, how to handle cases when the handle is called with Nil or a plain string. I am thinking about something like
proto handle(|c) {
if |c[0].^name ~~ /'Str'/ { # code for string }
else { {*} }
}
A better way to introspect ...
In general, a better way to do anything in any programming language is to not introspect if you can avoid it.
In general, in Raku, you can avoid manual introspection. See the section Introspection toward the end of this answer for further discussion.
... a capture
The best tool for getting the functionality that introspection of a capture provides is to use a signature. That's their main purpose in life.
I want to test the type of the first object in a signature
Use signatures:
proto handle(|) {*}
multi handle( Pod $node ) { ... }
multi handle( Str $string ) { ... }
multi handle( Nil ) { ... }
The following shows some ways I have found that work.
While they do what you want, they are essentially ignoring all of Raku's signature features. They reduce the signature to just a binding to the capture as a single structure; and then use manual introspection of that capture in the routine's body.
There's almost always a simpler and better way to do such things using signatures.
why does [|c[0].WHAT ~~ Rat, with c[0] == 3/2] not work?
I'll simplify first, then end up with what your code is doing:
say 3/2 ~~ Rat; # True
say (3/2) ~~ Rat; # True
say (3/2).WHAT ~~ Rat; # True
say |((3/2).WHAT ~~ Rat); # True
say (|(3/2).WHAT) ~~ Rat; # False
say |(3/2).WHAT ~~ Rat; # False
The last case is because | has a higher precedence than ~~.
Is there a better way than stringifying and testing for the string equivalent of the Type?
OMG yes.
Use the types, Luke.
(And in your use case, do so using signatures.)
Introspection
Compared to code that manually introspects incoming data in the body of a routine, appropriate use of signatures will typically:
Read better;
Generate better low-level code;
Be partially or fully evaluated during the compile phase.
If a language and its compiler have addressed a use case by providing a particular feature, such as signatures, then using that feature instead of introspection will generally lead to the above three benefits.
Languages/compilers can be broken into four categories, namely those that:
Do not do or allow any introspection;
Allow the compiler to introspect, but not devs;
Allow both the compiler and devs to introspect, but aim to make it a last resort, at least for devs;
Enable and encourage devs to introspect.
Raku(do) are in the third category. In the context of this SO, signatures are the primary feature that all but eliminates any need for a dev to manually introspect.
You can simply smartmatch to a type:
raku -e "sub a( *#c ) { say #c[0] ~~ Rat };a(3/2);a(2)"
True
False
Also I am using here a slurpy and not a capture, which is another alternative. Any way, with a single argument you're probably better off using type captures
raku -e "sub a( ::T $ ) { say ::T ~~ Rat };a(3/2);a(2)"
True
False
You can pull stuff out of a Capture in the signature.
# ( |C ( ::Type $a, +#b ) )
proto handle( | ( ::Type, +# ) ) {
if Type ~~ Str {
…
} else {
{*}
}
}
Basically a ::Foo before a parameter (or instead of it) is similar to .WHAT on that parameter.
It also becomes usable as a type descriptor.
sub foo ( ::Type $a ) {
my Type $b = $a;
}
It is an incredibly bad idea to compare types based on their name.
my $a = anon class Foo { has $.a }
my $b = anon class Foo { has $.b }
say $a.WHAT =:= $b.WHAT; # False
say $a.^name eq $b.^name; # True
As far as Raku is concerned it is entirely a coincidence that two types happen to have the same name.
If you do use the names, your code will be confused about the reality of the situation.

"Cannot assign to immutable value" when trying to assign to a string + role

Starting with the example in the Iterable doc page
role DNA does Iterable {
method iterator(){ self.comb.iterator }
};
my #a does DNA = 'GAATCC';
.say for #a; # OUTPUT: «G␤A␤A␤T␤C␤C␤»
I found it weird it's declared using the #, so I changed it to the natural way of declaring strings, $:
my $a does DNA = 'GAATCC';
But that fails with a somewhat bewildering "Cannot assign to an immutable value". No need to assign on the spot, so we can do:
my $a = 'GAATCC';
$a does DNA;
.say for $a;
Which just leaves mixing-in for later. But that just prints the string, without paying any attention to the Iterable mixin. Let's call it then explicitly:
.say for $a.iterator;
it does kinda the same thing as before, only it prints the value of $a.iterator, without actually calling the function:
<anon|69>.new
This looks like the same thing it's going on in this other question. Baseline question is I don't understand what role Iterable really does, and what for really does and when it is calling iterator on some object. Any idea?
I don't think this line does what you think it does:
my #a does DNA = 'GAATCC';
It is the same as:
my #a := [ 'GAATCC', ];
#a does DNA;
Basically the .comb call coerces the array into a Str, and splits that into characters.
If you instead did this:
my #a = 'GAATCC' but DNA;
Which is basically the same as
my #a := Seq.new(('GAATCC' but DNA).iterator).Array;
Note that # variables store Positional values not Iterable values.
The thing you want is
my $a = 'GAATCC' but DNA;
$a.map: &say;
If you want to be able to use for you can't use a variable with a $ sigil
my \a = 'GAATCC' but DNA;
.say for a;
You may want to add Seq list List etc methods to DNA.
role DNA does Iterable {
method iterator(){
self.comb.iterator
}
method Seq(){
Seq.new: self.iterator
}
method list(){
# self.Seq.list
List.from-iterator: self.iterator
}
}
my $a = 'GAATCC' but DNA;
.say for #$a;
Your question's title points to a bug. This answer covers the bug and also other implicit and explicit questions you asked.
Background
fails with a somewhat bewildering "Cannot assign to an immutable value".
I think that's a bug. Let's start with some code that works:
my $a = 42;
say $a; # 42
say WHAT $a; # (Int) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 42; # works fine
In the my declaraton $a gets BOUND to a new Scalar container. A Scalar container normally hides itself. If you ask WHAT type $a is, you actually get the type of the value currently ASSIGNED to the Scalar (the value it "contains"). You need VAR to access the container BOUND to $a. When you assign with = to a Scalar container you copy the assigned value into the container.
role foo {}
$a does foo; # changes the VALUE currently ASSIGNED to $a
# (NOT the VARIABLE that is BOUND to $a)
say $a; # 42 mixed in `foo` role is invisible
say WHAT $a; # (Int+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99
The does mixes the foo role into the 42. You can still assign to $a because it's still bound to a Scalar.
Note how these two uses of does have very different effects:
my $a does foo; # mixes `foo` into VARIABLE bound to $a
$a does foo; # mixes `foo` into VALUE assigned to $a
The bug
$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a; # Scalar+{foo}.new VALUE currently ASSIGNED to $a
say WHAT $a; # (Scalar+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo}) type of VARIABLE currently BOUND to $a
$a = 'uhoh'; # Cannot assign to an immutable value
The does mixes the foo role into the Scalar bound to $a. It seems that a Scalar with a mixin no longer successfully functions as a container and the assignment fails.
This currently looks to me like a bug.
my $b does foo; # BINDS mixed in VARIABLE to $b
$b = 'uhoh'; # Cannot assign to an immutable value
my $b does foo has the same result as my $b; $b.VAR does foo; so you get the same problem as above.
Other things you were confused about
my $a = 'GAATCC';
$a does DNA;
.say for $a;
just prints the string, without paying any attention to the Iterable mixin.
Because the $a VARIABLE is still bound to a Scalar (as explained in the Background section above), the VALUE that now has a DNA role mixed in is irrelevant per the decision process for uses about whether to call its argument's .iterator method.
Let's call it then explicitly ... prints the value of $a.iterator, without actually calling the function:
.say for $a.iterator;
Well it does call your DNA role's .iterator method. But that has another .iterator call at the end of the self.comb returned by your DNA role's iterator method so you're .saying that secondary .iterator.
Solutions that work today
I think Brad's answer nicely covers most of your options.
And I think your nice does DNA gist is as good as it gets with today's P6 if you want to use the $ sigil.
A solution that might one day work
In an ideal world all the sweetness in the P6 design would be fully realized in 6.c and the Rakudo compiler implementation of Perl 6. Perhaps that would include the ability to write this and get what you want:
class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;
The ... code would be about the same as what you have in your gist except that the DNA class would be a scalar container, and so the new method would instead be a STORE method or similar that would assign the passed value to a $!value attribute or some such when a value was assigned to the container using =.
But instead, you get:
is trait on $-sigil variable not yet implemented. Sorry.
So the closest you can get today to the ideal of = 'string' to change $a is to bind using := DNA.new('string') as you did in your gist.
Note that you can bind arbitrary composite containers to # and % sigil variables. So you can see how things are supposed to eventually work.