Re: subs and the type system

2020-07-21 Thread Theo van den Heuvel
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

2020-07-20 Thread Tobias Boege
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

2020-07-20 Thread Gianni Ceccarelli
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

2020-07-20 Thread Theo van den Heuvel

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

2020-07-20 Thread Tobias Boege
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

2020-07-20 Thread Gianni Ceccarelli
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