“位置太少";在宏定义中 [英] "Too few positionals" in macro definition

查看:96
本文介绍了“位置太少";在宏定义中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过这种方式创建一些使用(实验性)宏的示例:

I'm trying to create some examples of using (experimental) macros this way:

use experimental :macros;
macro cards_vars() { 
  (<hearts clubs diamonds spades> X~ 1..10).map: { "my \$$^x = False;" }  
};
cards_vars(); 
say $hearts1;

这将创建并运行宏,然后检查所定义的变量之一是否存在.但是我得到这个错误:

This creates and runs the macro, and then checks if one of the variable defined exists. But I get this error:

Too few positionals passed; expected 3 arguments but got 2

我什至不知道该错误来自何处.我认为它在cards_vars()中,但是我不知道是不是这种情况.声明不带括号的宏会产生相同的错误.

I don't even know where that error comes from. I think it's in cards_vars(), but I have no idea if that's the case or not. Declaring the macro without the parentheses yields the same error.

推荐答案

更新:需要明确的是,宏不仅是实验性的,而且还很初级且容易出错.有关此内容的更多信息,请参见 Moritz对另一个宏问题的回答.

Update: To be clear, macros are not just experimental but very rudimentary and buggy. For a little more about this, see Moritz's answer to another macros question.

让我们从打入代码开始:

Let's start with a golf of your code:

use experimental :macros;
macro foo { 42 }
foo

这会产生相同的编译时错误:

Too few positionals passed; expected 3 arguments but got 2

如果您从 AST 对象中返回了其他内容,则会收到此错误macro. 1 这是合理的,因为这是macro构造的整个要点.该错误消息并不令人赞叹-但是宏仍然是一项实验性功能.

You get this error if you return anything other than an AST object from a macro.1 Which is reasonable given that this is the entire point of the macro construct. The error message is less than awesome -- but then again macros are an experimental feature.

因此您需要返回AST.这是一种方法:

So you need to return an AST. Here's one way:

use experimental :macros;
macro foo { AST.new }
foo

这会产生运行时错误:

Useless use of constant value foo in sink context (line 3)

这表明宏已完成其工作.编译器已完成编译并进入运行时.

This shows that the macro has done its job. The compiler has completed compilation and proceeded to run-time.

显式返回AST对象是错误的处理方式.第一个原因在AST文档页面上给出:

Explicitly returning AST objects is the wrong way to proceed. The first reason is given on the AST doc page:

尚无为AST定义的API.希望这将作为宏工作的一部分的一部分出现.

第二个原因是,存在用于构造AST对象的更高级别的构造,即doc页面上和Scimon提到的quasi { ... }构造 3 :

The second reason is that there's a higher level construct for constructing AST objects, namely the quasi { ... } construct3 mentioned on the doc page and by Scimon:

use experimental :macros;
macro foo { quasi { 42 } }
say foo; # 42

quasi块告诉编译器将随附的语句编译为AST形式.

The quasi block tells the compiler to compile the enclosed statements into AST form.

请注意,结果不是与块相对应的AST.上面是与42对应的AST对象.

Note that the result isn't an AST corresponding to a block. In the above it's an AST object corresponding to 42.

所以,最后,回到您想做的事情.

So, finally, back to what you were trying to do.

简化:

use experimental :macros;
macro foo { quasi { my $bar } }
foo;
say $bar

产量:

Error while compiling ... Variable '$bar' is not declared

位置:

use experimental :macros;
macro foo { quasi { class bar {} } }
foo;
say bar; # (bar)

因此,最重要的是,词汇表声明目前无法坚持下去.

So, bottom line, lexical declarations currently fail to stick.

实验还没有完成.

Rakudo中的实验宏的创建者CarlMäsak正在 007 继续进行实验.如果您在GH仓库中遇到问题,卡尔会回答.

Carl Mäsak, the creator of the experimental macros in Rakudo, is continuing the experiment at 007. If you leave an issue at its GH repo Carl will answer.

1 当编译器遇到对它知道是宏 2 的例程的调用时,它将用其结果替换该宏调用.更详细的是编译器:

1 When the compiler encounters a call to a routine that it knows is a macro2 it replaces the macro call with its result. In more detail the compiler:

  • 将宏的所有参数编译为AST形式;

  • Compiles all the macro's arguments into AST form;

调用宏(在编译时),以其AST形式为其传递参数;

Calls the macro (at compile-time) passing it the arguments in their AST form;

运行应返回AST对象的宏例程(er,"ASTish" );

Runs the macro routine which is expected to return an AST object (er, "ASTish");

将生成的AST(ish)对象拼接到正在构造的整个AST中.

Splices the resulting AST(ish) object into the overall AST being constructed.

如果您不返回AST(ish)对象,则最后一步会出错,标题中会显示错误消息.

If you don't return an AST(ish) object the last step goes wrong with the error message in your title.

2 当前,如果在调用之后放置宏定义 ,则编译器不会意识到它是一个宏并将其视为普通例程:

2 Currently, if you put the macro definition after the call then the compiler doesn't realize it's a macro and treats it as an ordinary routine:

use experimental :macros;
say foo; # 42
macro foo { 42 }
say bar; # AST.new
macro bar { quasi { 42 } }
say bar; # 42

如果这会导致编译时错误,那就更好了.

It would presumably be better if this caused a compile-time error.

3 宏冠军Carl喜欢quasi这个词.它取材于口齿不清的遗产,取而代之的是数学遗产. Imo这是一个太可爱了"的选择,对于P6来说它真是太棒了.我的理由是,Perl哲学建议选择对初学者来说具有熟悉含义的关键字. 准"一词具有众所周知的普通英语含义,意思是有点,但不是真的".那根本没有帮助. (我向卡尔建议了toAST,但他更喜欢quasi.)

3 Carl, the macros champion, likes the word quasi. It draws from lisp heritage which draws from mathematics heritage. Imo it is a "too cute" choice that's a less than awesome fit for P6. My rationale is that Perl philosophy suggests choice of keywords with familiar meaning to newbies. The word "quasi" has a well known normal English connotation of meaning "sort of, but not really". That's not at all helpful. (I have suggested toAST to Carl but he prefers quasi.)

这篇关于“位置太少";在宏定义中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆