1

背景

加载下面的代码段会导致错误消息无法将“调用”应用于运行时计算值

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

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

问题

然而,我在听众中测试了我认为是两个等价的表达方式,它们工作得很好。

示例 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
4

1 回答 1

1

在这个例子中,有两个不同的问题在起作用。

第一个是在交互式代码中,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

于 2019-04-10T23:35:14.627 回答