Re: subs and the type system
Given that the signature is going to be more complex, it would be helpful if I do not need to repeat it for every member of the Walkable class. I tried using a constant to represent the signature so that I can create new Walkables without having to spell it out. Here is my code attempt (not working) use v6; class WalkData { has Str $.xyzzy; } constant \sgn-walkable = :(WalkData $d --> Any); subset Walkable of Callable where { .signature ~~ sgn-walkable }; sub walk(Walkable $task) { do-something($task, 17); } sub do-something(Walkable $task, Int $a) { $task($a); say $a; } my Walkable $xyzzify = -> :sgn-walkable { say $d.xyzzy }; walk($xyzzify); I get this error. ===SORRY!=== Expression needs parens to avoid gobbling block at /.../walkable.pl6:10 --> ble where { .signature ~~ sgn-walkable }⏏; Missing block (apparently claimed by expression) at /.../walkable.pl6:21 --> my Walkable $xyzzify = ⏏-> :sgn-walkable { say $d.xyzzy }; I tried to use the scalar sigil instead of the sigilless constant. To no avail. I am hoping for a form that allows me to define Walkables as such. Thanks, Theo van den Heuvel Tobias Boege schreef op 2020-07-20 14:00: On Mon, 20 Jul 2020, Theo van den Heuvel wrote: Hi gurus, after looking at the documentation on Sub, Signature and the raku type system I find myself unable to constrain the types of functions in the way I think I need. The situation: I have a function, let's call in 'walker', whose first parameter is a callback. I wish to express that only callbacks with a certain Signature and return type are acceptable. Let's say the callback should follow :(Numeric $n --> Numeric). My callback is going to be more complicated, but for simplicity sake. I was hoping to be able to use a named type of function with this signature. I know I can say my $sig = :(Numeric $n --> Numeric); but my attempts to use $sig fail. I found no example of an application beyond smartmatching. [...] but I was hoping for an explicit type, maybe using class, or subset or roles. I hope to say soemething like sub walker(Walkable , ...) What am I missing here? You said that you know how to check signatures via smartmatching. Smartmatching is great, there isn't much to know beyond it. The way to shoehorn smartmatching into the type system is `subset`: subset Walkable of Callable where { .signature ~~ :(Numeric --> Numeric) }; If your callback signature is more complicated, all the more reason to give it a name via subset. You can use it now almost like you wanted: sub walker (Walkable $w) { say $w($_) for 1..10 } walker(-> Numeric $x --> Numeric { $x.sqrt }); # WORKS walker(-> $x { $x.sqrt }); # DOESN'T You cannot write `Walkable ` in the signature of because the combination of a type and the &-sigil apparently means that `` should be Callable and return a Walkable. That's why I use the $-sigil. [*] Note that if you constrain the signature of a Callable, then you have to provide the appropriate signature statically, as demonstrated. Best, Tobias [*] N.B. I failed to find a reference for this in the documentation. I discovered it by writing `sub walker (Int )` and provoking a type checking error which told me that it was expecting `Callable[Int]`. (That was also my gut feeling.) According to source code, Callable is a parametric role in Rakudo whose first parameter indeed is the return type. This is all somewhat nebulous to me (how does the Callable- parametric way to specify return type compare with smartmatching against .signature, for example? They don't seem equivalent!), so I stick with the $-sigil.
Re: subs and the type system
On Mon, 20 Jul 2020, Gianni Ceccarelli wrote: > Aside: > > ``(sub (Int $ --> Int) {}) ~~ Walkable`` is false, because > ``:(Int $ --> Int) ~~ :(Numeric $ --> Numeric)`` is false, which is > correct because function subtypes should be contravariant in the parameter > types and covariant in the return type (i.e. if the caller passes a > Numeric, the callback should accept a Numeric or a *more general* > type, and if the caller expects a Numeric back, the callback should > return a Numeric or a *more specific* type). > > But then ``:(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)`` is also > false, and I feel like it should be true. Opinions? > My _opinion_ is that you are right, be it only because there exist words reminiscent of category theory that describe your desired behavior :-) But the source code of a Signature smartmatching another Signature [1] explicitly uses smartmatching for the parameter types and uses the unforgiving container identity operator to compare the return types: 91 return False unless self.returns =:= $topic.returns; The `eqv` implementation for two Signatures uses `=:=` as well, so this restriction seems deliberate. Changing the `=:=` to a `.does` call makes your code snippet work: $ ./rakudo-m -e 'say :(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)' True but it creates problems with roast that appear to spread multiple parts of the language. Failing tests are: t/spec/S10-packages/precompilation.rakudo.moar (Wstat: 65280 Tests: 32 Failed: 0) t/spec/S02-types/compact.rakudo.moar(Wstat: 256 Tests: 0 Failed: 0) t/spec/S02-types/native.rakudo.moar (Wstat: 256 Tests: 0 Failed: 0) t/spec/S06-currying/positional.t(Wstat: 256 Tests: 0 Failed: 0) t/spec/S06-signature/closure-parameters.rakudo.moar (Wstat: 256 Tests: 21 Failed: 1) t/spec/S09-typed-arrays/native-int.rakudo.moar (Wstat: 65280 Tests: 169 Failed: 0) t/spec/S09-typed-arrays/native-num.rakudo.moar (Wstat: 65280 Tests: 157 Failed: 0) t/spec/S09-typed-arrays/native.t(Wstat: 65280 Tests: 3 Failed: 0) t/spec/S17-lowlevel/cas-int.t (Wstat: 256 Tests: 0 Failed: 0) t/spec/S17-promise/nonblocking-await.t (Wstat: 256 Tests: 0 Failed: 0) t/spec/S32-array/splice.rakudo.moar (Wstat: 256 Tests: 0 Failed: 0) t/spec/S32-basics/xxPOS-native.t(Wstat: 65280 Tests: 15 Failed: 0) t/spec/S32-list/iterator.t (Wstat: 65280 Tests: 48 Failed: 0) t/spec/integration/precompiled.t(Wstat: 256 Tests: 9 Failed: 1) Some failures are very dubious like this error, resulting in the test not even starting (there are multiple of this sort, as you can see): $ ./rakudo-m -Ilib t/spec/S06-currying/positional.t ===SORRY!=== No appropriate parametric role variant available for 'array::intarray' Maybe my small changes (patch attached) create inconsistencies with these other parts of the language (oftentimes related to native types?), or maybe the test suite relies on (hence specifies) non-covariance. I don't know. Best, Tobias [1] https://github.com/rakudo/rakudo/blob/master/src/core.c/Signature.pm6#L34-L93 PS: I want to note that my first attempt naïvely replaced the `=:=` with `~~` but this set roast even more on fire which I think is related to `~~` autothreading on junctions, as opposed to `=:=` and `.does`. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk diff --git a/src/core.c/Signature.pm6 b/src/core.c/Signature.pm6 index ea2b5cabe..72eff7bdd 100644 --- a/src/core.c/Signature.pm6 +++ b/src/core.c/Signature.pm6 @@ -88,7 +88,7 @@ my class Signature { # declared in BOOTSTRAP return False unless $hasslurpy; } } -return False unless self.returns =:= $topic.returns; +return False unless $topic.returns.does(self.returns); True; } @@ -160,7 +160,7 @@ multi sub infix:(Signature:D \a, Signature:D \b) { return False unless a.WHAT =:= b.WHAT; # different return -return False unless a.returns =:= b.returns; +return False unless a.returns.does(b.returns); # arity or count mismatch return False if a.arity != b.arity || a.count != b.count;
Re: subs and the type system
On Mon, 20 Jul 2020 14:00:33 +0200 Tobias Boege wrote: > You cannot write `Walkable ` in the signature of because the > combination of a type and the &-sigil apparently means that `` > should be Callable and return a Walkable. That's why I use the > $-sigil. Aha! That's the bit I got wrong, thank you! with that change, my example works. I'd still like opinions on the subtyping situation between `Signature` -- Dakkar - GPG public key fingerprint = A071 E618 DD2C 5901 9574 6FE2 40EA 9883 7519 3F88 key id = 0x75193F88
Re: subs and the type system
Thanks Gianni and Tobias, This is very helpful. One minor follow-up. If I define by signature like this: my $sgn-walkable = :(Numeric $n --> Numeric); I could not define Walkable subs like this, could I? my Walkable $crawlback = ... Thanks, Theo Tobias Boege schreef op 2020-07-20 14:00: On Mon, 20 Jul 2020, Theo van den Heuvel wrote: Hi gurus, after looking at the documentation on Sub, Signature and the raku type system I find myself unable to constrain the types of functions in the way I think I need. The situation: I have a function, let's call in 'walker', whose first parameter is a callback. I wish to express that only callbacks with a certain Signature and return type are acceptable. Let's say the callback should follow :(Numeric $n --> Numeric). My callback is going to be more complicated, but for simplicity sake. I was hoping to be able to use a named type of function with this signature. I know I can say my $sig = :(Numeric $n --> Numeric); but my attempts to use $sig fail. I found no example of an application beyond smartmatching. [...] but I was hoping for an explicit type, maybe using class, or subset or roles. I hope to say soemething like sub walker(Walkable , ...) What am I missing here? You said that you know how to check signatures via smartmatching. Smartmatching is great, there isn't much to know beyond it. The way to shoehorn smartmatching into the type system is `subset`: subset Walkable of Callable where { .signature ~~ :(Numeric --> Numeric) }; If your callback signature is more complicated, all the more reason to give it a name via subset. You can use it now almost like you wanted: sub walker (Walkable $w) { say $w($_) for 1..10 } walker(-> Numeric $x --> Numeric { $x.sqrt }); # WORKS walker(-> $x { $x.sqrt }); # DOESN'T You cannot write `Walkable ` in the signature of because the combination of a type and the &-sigil apparently means that `` should be Callable and return a Walkable. That's why I use the $-sigil. [*] Note that if you constrain the signature of a Callable, then you have to provide the appropriate signature statically, as demonstrated. Best, Tobias [*] N.B. I failed to find a reference for this in the documentation. I discovered it by writing `sub walker (Int )` and provoking a type checking error which told me that it was expecting `Callable[Int]`. (That was also my gut feeling.) According to source code, Callable is a parametric role in Rakudo whose first parameter indeed is the return type. This is all somewhat nebulous to me (how does the Callable- parametric way to specify return type compare with smartmatching against .signature, for example? They don't seem equivalent!), so I stick with the $-sigil.
Re: subs and the type system
On Mon, 20 Jul 2020, Theo van den Heuvel wrote: > Hi gurus, > > after looking at the documentation on Sub, Signature and the raku type > system I find myself unable to constrain the types of functions in the way I > think I need. > > The situation: I have a function, let's call in 'walker', whose first > parameter is a callback. > I wish to express that only callbacks with a certain Signature and return > type are acceptable. > Let's say the callback should follow :(Numeric $n --> Numeric). My callback > is going to be more complicated, but for simplicity sake. > > I was hoping to be able to use a named type of function with this signature. > I know I can say > > my $sig = :(Numeric $n --> Numeric); > > but my attempts to use $sig fail. I found no example of an application > beyond smartmatching. > > [...] > > but I was hoping for an explicit type, maybe using class, or subset or > roles. > I hope to say soemething like > > sub walker(Walkable , ...) > > What am I missing here? > You said that you know how to check signatures via smartmatching. Smartmatching is great, there isn't much to know beyond it. The way to shoehorn smartmatching into the type system is `subset`: subset Walkable of Callable where { .signature ~~ :(Numeric --> Numeric) }; If your callback signature is more complicated, all the more reason to give it a name via subset. You can use it now almost like you wanted: sub walker (Walkable $w) { say $w($_) for 1..10 } walker(-> Numeric $x --> Numeric { $x.sqrt }); # WORKS walker(-> $x { $x.sqrt }); # DOESN'T You cannot write `Walkable ` in the signature of because the combination of a type and the &-sigil apparently means that `` should be Callable and return a Walkable. That's why I use the $-sigil. [*] Note that if you constrain the signature of a Callable, then you have to provide the appropriate signature statically, as demonstrated. Best, Tobias [*] N.B. I failed to find a reference for this in the documentation. I discovered it by writing `sub walker (Int )` and provoking a type checking error which told me that it was expecting `Callable[Int]`. (That was also my gut feeling.) According to source code, Callable is a parametric role in Rakudo whose first parameter indeed is the return type. This is all somewhat nebulous to me (how does the Callable- parametric way to specify return type compare with smartmatching against .signature, for example? They don't seem equivalent!), so I stick with the $-sigil. -- "There's an old saying: Don't change anything... ever!" -- Mr. Monk
Re: subs and the type system
On Mon, 20 Jul 2020 12:37:33 +0200 Theo van den Heuvel wrote: > The situation: I have a function, let's call in 'walker', whose first > parameter is a callback. > I wish to express that only callbacks with a certain Signature and > return type are acceptable. > Let's say the callback should follow :(Numeric $n --> Numeric). My > callback is going to be more complicated, but for simplicity sake. Interesting problem! I tried:: use v6.d; subset Walkable of Callable where { $^c.signature ~~ :(Numeric $--> Numeric) }; sub walker(Walkable ) { say callback(1); } sub callback(Numeric $x --> Numeric) { 1+$x } say 'is Callable? ', ~~ Callable; say 'does the signature match? ', ~~ :(Numeric $n --> Numeric); say 'is Walkable? ', ~~ Walkable; walker(); which prints:: is Callable? True does the signature match? True is Walkable? True Type check failed in binding to parameter ''; expected Walkable but got Sub+{Callable[Numeric]} (sub callback (Numeric...) in sub walker at /tmp/s.raku line 5 in block at /tmp/s.raku line 15 which is quite surprising to me. Aside: ``(sub (Int $ --> Int) {}) ~~ Walkable`` is false, because ``:(Int $ --> Int) ~~ :(Numeric $ --> Numeric)`` is false, which is correct because function subtypes should be contravariant in the parameter types and covariant in the return type (i.e. if the caller passes a Numeric, the callback should accept a Numeric or a *more general* type, and if the caller expects a Numeric back, the callback should return a Numeric or a *more specific* type). But then ``:(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)`` is also false, and I feel like it should be true. Opinions? -- Dakkar - GPG public key fingerprint = A071 E618 DD2C 5901 9574 6FE2 40EA 9883 7519 3F88 key id = 0x75193F88