tope Ok, I am really struggling with this. 13:37
are the dispatches in modules resolved uhh statically, without taking into account there might be a new candidate to &infix:<+> which handles a subclass of `Int`?
```raku 13:40
my $F = ZMod.new(modulus=>get-prime(2**7 .. 2**8));
my $a = $F(50);
my $b = $F(11);
"$a ** 2 = {$a**2} (mod {$F.modulus})".say;
"$b - $a = {$b-$a} (mod {$F.modulus})".say;
my $arr1 = (1..4).map(* * $a);
my $arr2 = (1..4).map($b ** *);
"<$arr1> + <$arr2> = <{$arr1 »+« $arr2}> (mod {$F.modulus})".say;
use Math::Vector;
my $vec1 = Math::Vector($arr1);
my $vec2 = Math::Vector($arr2);
even though the last two output lines should really be the same, as I am literally replicating what the infix:<+>(Math::Vector, Math::Vector) is doing 13:43
and $vec1[0].WHAT reports it is indeed ZModInt etc 13:45
but something happens somewhere so my `&infix:<+>(ZModInt, Int --> ZModInt)` isn't used anymore but instead it goes back to using `&infix:<+>(Int, Int --> Int)` and types are reset back to Ints 13:49
15:08 discord-raku-bot left, discord-raku-bot joined
guifa tope#9134: If I'm following correctly, new candidates to &infix only apply in the lexical scope. You'd need to wrap the infix to have it applied at a global level 16:36
tope hmm, what does 'wrap the infix' mean? 16:46
guifa wrapping is something you can do to any routine to intervene on all calls to it. You can then modify variables before redispatching to the original or you can eschew it entirely. 16:58
m: sub a ($b) { say "Called A with $b"; return 42 }; &a.wrap( sub ($b) { say "Start wrapper, got $b"; my $result = callsame; say "End wrapper (captured $result)"; return 100 }); say a(1) 17:00
camelia Start wrapper, got 1
Called A with 1
End wrapper (captured 42)
100
tope I meant, would that entail wrapping the `&infix:<+>` itself? so basically I have to do manual dispatch? Or wrapping the `(Int,Int)` candidate on `&infix:<+>`? 17:02
and do manual dispatch in the latter
guifa in your case, I'd use &infix:<+>.wrap: sub (\a, \b) { return callsame unless (a, b) ~~ (YourClass, YourClass); #`[now your code here for the special case] }
tope I would like to 'eat' `Int` arguments so only if one of the arguments is YourClass is the trigger, but yeah, ok, I gotcha. 17:04
basically I'd like to make my own arithmetic-ish types (i.e. rings) that subclass the built-in types (e.g. modular numbers or 𝔽_p would subclass `Int`, polynomials would probably subclass `Array`, etc), which "most of the time" acts like the underlying type (e.g. for purposes of converting to string or comparisons etc), but still be able to use them in external packages to build matrices, vectors, of 17:06
is what I'm trying to do
hmm, this wrapper, doesn't that also add undue overhead to _all_ `+` everywhere and anywhere? 17:10
guifa Yeah. I tried seeing if I could do it on just the Int candidates but it failed for some reason, and there's not a way (AFAIK) to add a new candidate to a multi 17:20
tope hmm I tried ``` 17:21
&infix:<+>.wrap: sub (\a, \b) {
return a.parent.(Int.new(a) + Int.new(b)) if a ~~ ZModInt;
return b.parent.(a + Int.new(b)) if b ~~ ZModInt;
callsame
}
``` and so on for all the arithmetic ops. my local arithmetic still works but `Math::Vector($arr1) + Math::Vector($arr2)` doesn't, still resets all the types to regular `Int`.. so maybe there's something else doing on.
```
> $vec1[0] * 5
17
> $vec1 * 5
Math::Vector.new(250, 500, 750, 1000)
```
it's still my `ZModInt`s in the vector, but somehow when it does the »...« hyper-stuff or whatever on its side they get reset(?) 17:22
guifa Hmm, I'd need to do a bit more digging on that 17:23
tope guifa: gist.github.com/fsh/42bd6d7c91bbc6...3f7aa5496a there's the code I was working with for reference / in case I was doing really anything stupid 17:29
guifa: gist.github.com/fsh/42bd6d7c91bbc6...3f7aa5496a there's the code I was working with for reference / in case I was doing something really stupid
guifa Extending built ins is … tricky. 17:41
But one small code style thing in the meantime 17:48
a.parent.(Int.new(a) + Int.new(b)) if a ~~ ZModInt; could be written as a.parent(a.Int, b.Int), a lot less line noise 17:49
tope ordinarily yes, I just hadn't gotten around to overloading/adding Int method: 17:52
```
> $a.WHAT
(ZModInt)
> $a.Int.WHAT
(ZModInt)
```
i just needed them to be 'actual' Ints for normal dispatch to occur 17:53
and yes, tricky indeed. I'm beginning to get the impression that the stuff I want to do is sort of a hard problem in Raku(?), which is unfortunate as there's a lot in Raku that I very much like over my main scripting language Python. (Tho this kind of thing (subclass `int`, make custom `dict`s, `list`s etc) is pretty easy/straightforward in Python -- or maybe only cause I'm more familiar with it.) 17:55
as in Python `a+b` calls a method `a.__add__` so the arithmetic stuff is sort of built into the class types 17:56
guifa AHA 18:01
I found a simpler way than wrapping, and it might even be faster 18:02
tope cool, lay it on me 18:03
guifa m: class A { }; role B { multi method CALL-ME(A $, A $) { 'special' } }; &infix:<+> does B; say A + A; say 1 + 1;
camelia special
2
guifa that mixin will still apply globally, and at mixin the method table will be updated with the additional methods 18:05
so you shouldn't have a huge speed hit (I mean, + already has like 20 candidates, so two more won't kill it, especially with how the dispatcher optimizes out checks when it's safe)
That probably won't solve the problem with Math::Vector depending on how it's written internally, though. But at least will make your coding life easier ha 18:06
tope hmmm, having some trouble still. firstly I want both `CALL-ME(ZModInt, Int)` and `CALL-ME(Int, ZModInt)`, so I add those to a role and do the `does ZModIntAddition`, say. then it complains ZModInt, ZModInt is ambiguous, ok, so I add `is default` (or add CALL-ME(ZModInt, ZModInt)). but now I'm getting it can't match `(Int,Int)`? 18:27
```
Cannot resolve caller CALL-ME(Sub+{is-pure}+{Precedence}+{ZModIntSub}:D: Int:D, Int:D); none of these signatures match:
(Sub+{is-pure}+{Precedence}+{ZModIntSub}: ZModInt \a, ZModInt \b, *%_)
(Sub+{is-pure}+{Precedence}+{ZModIntSub}: ZModInt \a, Int \b, *%_)
(Sub+{is-pure}+{Precedence}+{ZModIntSub}: Int \a, ZModInt \b, *%_)
```
not sure if I did it right
guifa it won't match (Int,Int) because there's a more specific candidate: (Int:D, Int:D) in core. But my guess is you want Int + Int to dispatch to core, so just leave it off entirely: 18:33
m: class ZModInt is Int { }; role ZModIntAddition { multi method CALL-ME(ZModInt $, Int $) { 1 }; multi method CALL-ME(Int $, ZModInt $) { 2 }; multi method CALL-ME(ZModInt $, ZModInt $) { 3 } }; &infix:<+> does ZModIntAddition; say ZModInt + Int; say Int + ZModInt; say ZModInt + ZModInt; say 2 + 2
camelia 1
2
3
4
guifa that's all four combinations dispatching correctly
tope hmmmm I can't see the difference between my code and yours, yet mine doesn't work.. 18:40
guifa I can take a look at it again in a little bit if you can't figure it out -- gotta to be AFK for a few hours I'm afraid 18:41
tope ```
role ZModIntAdd {
multi method CALL-ME(ZModInt $a, ZModInt $b) {
$a.parent.(Int.new($a) + Int.new($b))
}
multi method CALL-ME(ZModInt $a, Int $b) {
$a.parent.(Int.new($a) + $b)
}
multi method CALL-ME(Int $a, ZModInt $b) {
$b.parent.($a + Int.new($b))
}
};