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)) | |||
} | |||
}; |