Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl 6 multi methods never match expected signature

I have a class with two multi methods (multi submit).

I call my multi like this:

$perspective.submit(:message($message.content));

Which gets shipped off to my class:

my $perspective-api = API::Perspective.new(:api-key(%*ENV<PERSPECTIVE_API_KEY>));

proto method submit (|) {*}

multi method submit(Str :$message!, MODEL :@models = TOXICITY) {
    my $score = $perspective-api.analyze(:@models, :comment($message));
    say @models Z=> $score<attributeScores>{@models}.map: *<summaryScore><value>;

multi method submit(Str :$name!, MODEL :@models = TOXICITY) {
    my $score = $perspective-api.analyze(:@models, :comment($name));
    say @models Z=> $score<attributeScores>{@models}.map: *<summaryScore><value>;
}

However I always get the following response:

Died because of the exception:
    Cannot resolve caller AUTOGEN(Rose::ContentAnalysis::Perspective:D: :message(Str)); none of these signatures match:
        (Rose::ContentAnalysis::Perspective: Str :$message!, MODEL :@models = MODEL::TOXICITY, *%_)
        (Rose::ContentAnalysis::Perspective: Str :$name!, MODEL :@models = MODEL::TOXICITY, *%_)

Despite my named argument (:message) being a Str as required and @models having a default declared.

like image 525
kawaii Avatar asked Jun 25 '19 15:06

kawaii


1 Answers

Multiple dispatch works in two phases:

  • Considering the number of positional parameters and their types
  • If there are any where clauses, named parameters, or sub-signatures, doing a test bind of the signature to see if it would match

The second phase will reject the candidate if it fails to bind for any reason. One such reason, and I believe the cause of the issue here, is that the default value is wrongly typed. For example, in:

multi m(:@x = "not-an-array") { }
m()

We get an error:

Cannot resolve caller m(...); none of these signatures match:
    (:@x = "not-an-array")
  in block <unit> at -e line 1

But changing it to:

multi m(:@x = ["an-array"]) { }
m()

Works fine. (Note that while a default value uses =, it's actually a binding, not an assignment.)

In the case in the question there's this:

MODEL :@models = TOXICITY

Looking at the module source the code is taken from, I see:

enum MODEL is export (
        <TOXICITY SEVERE_TOXICITY TOXICITY_FAST IDENTITY_ATTACK
        INSULT PROFANITY SEXUALLY_EXPLICIT THREAT FLIRTATION
        ATTACK_ON_AUTHOR ATTACK_ON_COMMENTER INCOHERENT INFLAMMATORY
        LIKELY_TO_REJECT OBSCENE SPAM UNSUBSTANTIAL>
);

Thus TOXICITY is just an Int, but what's expected is a typed array of MODEL values.

Thus, if you do this:

multi method submit(Str :$message!, MODEL :@models = Array[MODEL](TOXICITY)) {

It should work.

like image 112
Jonathan Worthington Avatar answered Sep 27 '22 17:09

Jonathan Worthington