使用由另一个词计算的引用会导致编译错误

Using quotation computed by another word causes compilation error

背景

加载下面的代码片段会导致错误消息无法将 "call" 应用于 运行 时间计算值:

: subtract-sum ( seq -- quot: ( n -- n ) ) sum '[ _ - ] ;
: subtract-sum-seq ( seq -- x ) dup subtract-sum map ;

我的理解是这是预期的行为,因为在 map 中对 call 的内部调用需要输入和输出已处理的报价在编译时出现。

问题

但是我在 listener 中测试了我认为是两个等价的表达式,它们工作得很好。

示例 1:

# : subtract-sum ( seq -- quot: ( n -- n ) ) sum '[ _ - ] ;
# : subtract-sum-seq ( seq -- seq call ) dup subtract-sum ;
# { 1 2 3 4 } subtract-sum-seq
{ 1 2 3 4 }
[ 10 - ]
# map
{ -9 -8 -7 -6 }

示例 2:

# : subtract-sum-seq ( seq -- x ) dup '[ _ - ] map ;
# { 1 2 3 4 } subtract-sum-seq
{ -9 -8 -7 -6 }

问题

原始代码与导致第一个错误但其他两个没有错误的工作示例之间有什么区别?显然这里的引语似乎有些地方我不理解。

附加信息

有趣的是,我试图将第一个示例中对 map 的调用包装到一个单词中,结果导致与原始代码相同的错误:

# { 1 2 3 4 } subtract-avg-seq map
{ -9 -8 -7 -6 }
# : apply ( -- seq ) { 1 2 3 4 } subtract-avg-seq map ; ! error: Cannot apply "call" to a run-time computed value

这个例子中有两个不同的问题。

首先是在交互式代码中,Listener 不会检查引用的堆栈效应,但是当代码在定义中编译时会检查它们。这就是在 Listener 中手动扩展单词的原因。

第二个问题是在大多数单词中忽略了为引用声明的嵌套效果。您可以将 ( n -- quot: ( n -- n ) ) 替换为 ( n -- q ),它的工作原理相同。

在这种情况下,第一个单词中的引用声明不会传递到第二个单词中。这就是为什么即使理论上都是正确的,编译器也无法证明;它只是不知道报价的影响。

解决办法是在调用处声明报价的效果:

: subtract-sum ( seq -- quot: ( n -- n ) ) sum '[ _ - ] ;
: subtract-sum-seq ( seq -- x ) dup subtract-sum [ call( n -- n ) ] curry map ;
{ 1 2 3 4 } subtract-sum-seq .

! -> { -9 -8 -7 -6 }

https://docs.factorcode.org/content/article-effects.html

https://docs.factorcode.org/content/article-inference-escape.html