【问题标题】:Interpolate without creating a String context in Raku?插值而不在 Raku 中创建字符串上下文?
【发布时间】:2026-02-03 21:00:01
【问题描述】:

如果我有一个变量my $a = True,那么我会从以下代码中得到这个输出:

say «a list of words foo $a bar baz».raku; 
# OUTPUT: ("a", "list", "of", "words", "foo", "True", "bar", "baz")

也就是说,即使结果是 List,元素 True 在被包含在列表中之前也会被字符串化 - 列表包含 "True",而不是 True。有什么办法可以在仍然使用插值的同时避免这种字符串化?

如果$a 是我定义的类(因此可以为其编写Str 方法)而不是Bool,是否有办法做到这一点?

(我知道我可以写更详细的("a", "list", "of", "words", "foo", $a, "bar", "baz")«a list of words foo».Slip, $a, «bar baz».Slip,但我想问是否有办法仍然使用插值)。

【问题讨论】:

  • 我有两个理由问这个问题,尽管我相信答案是“不,那是不可能的”。首先,我可能错了——就像happened before 一样,我认为 Raku 不能做某事。其次,有这样的答案说“那是不可能的”可以避免其他用户搜索正确的语法来做一些永远不会工作的事情。 (并且列出 Raku 不能做的事情不适合文档。)如果您觉得这类问题很烦人,请告诉我;如果没有,我可能会在接下来的几天内问几个。
  • “当我认为 Raku 不能做某事的时候。” Raku 不能改变物理定律,但除此之外,没有 PL 能做的比 Raku 能做的更多。它包含一个图灵完备的 GPL。唯一的限制是诸如何时、如何有效以及如何轻松地完成它所做的事情。 Raku 支持MSP,因此 Raku 可以在编译时完成,无论“它”是什么。标准 Raku 已经附带了一些功能,使一些 MSP 任务变得容易。 RakuAST 以及在它之上构建的工具将使基本上所有 MSP 任务变得更容易,包括用于甜蜜和性能的 MSP。
  • "如果您觉得这类问题烦人,请告诉我;如果不是,我可能会在接下来的几天内问几个。"我认为您对此提出的一百个深思熟虑的 Q 将是一件很棒的事情,尽管我敦促您将它们分散开来,等到您发布的 Q 得到您接受的答案,或者至少 N 天过去了(其中 N=2 感觉是正确的)没有接受的答案,然后发布下一个。
  • > “没有 PL 比 Raku 能做的更多。它包含一个图灵完备的 GPL。”我的意思是,这技术上是正确的。但是对于“Raku”和“不能做”的相当合理的含义,我会说 Raku 目前不能做的事情(尽管它可以做的更多!)。例如,“Raku”目前“不能”知道sub f(--> Int) { 'Oops' } 在编译时是无效的。我并不是说不可能为 Raku 编写静态分析器。显然不是。我并不是说 Raku 永远无法做到这一点。我的意思是,现在,it can't
  • .@codesections 当然。虽然现在你可以写BEGIN { f },结果是编译时错误。明确地说,我得到了,并且得到了,你曾经和现在在说什么。我的评论不是针对您个人,而是主要针对可能误解什么可以做什么和不可以做什么的后来读者。一些 PL 将永远能够授权开发人员将内容从运行时转移到编译时,但 Raku 已经做到了,而且还会有更多。正如您所说,开发人员可以编写一个静态分析器,并且正如 jnthn 所指出的,近期路线图的一部分使得将类型检查器实现为模块成为可能。

标签: string raku string-interpolation rakudo


【解决方案1】:

插值是将一个东西放入一个字符串中。

"a b c $thing d e f"

它首先将事物本身变成一个字符串,然后将其周围的其余字符串连接起来。

基本上上面编译成这段代码:

infix:<~>( 「a b c 」, $thing.Str, 「 d e f」 )

« a b c $thing »

简称:

Q :double :quotewords « a b c $thing d e f »

即使用Quoting DSL,打开:double 引用语义(“”)并打开:quotewords

:quotewords 是将字符串拆分为各个部分的功能。 它只有在变成字符串后才会发生。

想象一下上面的编译成:

Internals::quotewords( infix:<~>( 「 a b c 」, $thing.Str, 「 d e f 」 ) )

除了使用.Slip 或前缀| 之外,还有另一种方法可以得到你想要的。

flat «a list of words foo», $a, «bar baz»

引用 DSL 的全部目的是生成一个字符串。

也就是说,:words:quotewords:val 都对其进行了更改,使其返回的不是单个字符串。 他们的想法是改变 DSL。

所以也许你可以说服足够多的人相信这样的改变是值得的。 这是一个很大的也许

它可能会破坏许多现有的代码库,因此您将面临一场艰苦的战斗。

【讨论】:

  • 或者,更好的是,只创建一个专门的 DSL ^_^(这提醒我要根据 binex 的经验重新编写我的 DSL 操作指南,目前该操作一直搁置到 RakuAST)
  • 谢谢,这一切都是有道理的,而且是关于我所怀疑的;确认非常有帮助。 “基本上上面的代码编译成这个代码:infix:&lt;~&gt;( 「a b c 」, $thing.Str, 「 d e f」 )”。当我问我是否可以避免对 $thing 进行字符串化(如果它是我控制的类型)时,我正在考虑这种代码——毕竟,我可以理论上写一个 .Str 方法t 返回Str。但是,既然您指出了使用 infix:&lt;~&gt; 的方式,那么该路径似乎不太可能起作用 - 如果它有任何作用,它可能只会破坏插值。
【解决方案2】:

这里发生的事情与引用无关,而与context 有很大关系。正如@brad-gilbert 所指出的那样,通过将~ 放在前面的任何事情都会将变量强制转换为String 上下文。

但这可以回答您的第二个问题:

如果 $a 是我定义的类(因此可以为其编写 Str 方法)而不是 Bool,是否有办法做到这一点?

理论上,这样的事情应该可以工作:

class A { 
    has Bool $.foo;
    method Str { $.foo }
};
my $a = A.new( :foo(True) );
say «a b $a».raku

唉,这会返回«No such method 'WORDS_AUTODEREF' for invocant of type 'Bool'␤,所以它可能需要做一些工作(或者我可能遇到了一些错误)。因此,就目前而言,对于您的确切示例,这是一个 nanswer。事实上,只有Strs 有这个方法,所以我认为暂时,除非你费心为一个类创建那个专门的方法,否则很难做到。

【讨论】:

    最近更新 更多