使用字符串创建红色语言中的单词和路径
Use strings to create words and paths in Red language
我在 namelist
中有字符串,它们对应于应用程序中的变量和字段名称。
函数应该从namelist中读取字符串,加上一个'f'得到field_names,然后把变量值放在相应的字段中。
我试过下面的代码,没有给出任何错误,但也不起作用:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
一般来说:将字符串转换为 WORD!s (例如 to-word "foo"
) 很容易。然而,神奇地创造这个词可能很难!引用绑定到 "the variable you meant"。这样做的巧妙原因与 没有范围 这一事实有关。参见:
Is there a overall explanation about definitional scoping in Rebol and Red
因此,无论如何,您尝试做的事情都会有点狡猾。有更好的方法。但是为了避免不问这个问题,我将解释这里发生了什么以及如何以您尝试的方式修复它。
更正后的版本仅用于教学目的。请换一种方式。
compose rejoin [namelist/:i "f/text"]
REJOIN 应用于块,并合并内容,结果类型 loosely 基于第一个元素。 (这是一个 questionable operation,但在 Rebol 代码中历来很流行。)
由于 namelist/:i
是一个字符串,您的 REJOIN 将生成一个字符串...并且该字符串最终将传递给 COMPOSE。但 COMPOSE 旨在应用于 BLOCK!s... 并在其中搜索带括号的组 inside,评估它们,同时保留其余代码。它是一种块模板系统,对其他类型的输入没有影响......所以你会得到相同的字符串。
TO-SET-PATH 因此被输入了一个字符串! (例如 "var1f/text")。我什至不知道路径转换接受字符串。我发现此操作的行为令人费解,因为它显然加载了字符串,然后使其成为长度为 1 SET-PATH!.
的奇异元素
>> p: to-set-path "foo/bar"
== foo/bar: ;-- huh? really, did that work?
>> type? p
== set-path! ;-- ok, good, I guess.
>> length? p
== 1 ;-- wait, what?
>> type? first p
== path! ;-- a PATH! inside a SET-PATH!...?
>> length? first p
== 2
>> type? first first p
== word!
>> foo: 10
>> get first first p
== 10 ;-- well, at least it's bound
那可不是SET-PATH那种!你要;你想要一个 SET-PATH! 2个字!元素。转换块!设置路径!将是这样做的一种方式。
to-set-path compose [(load rejoin [namelist/:i "f"]) text]
现在我们看到 COMPOSE 被正确使用了,它将 运行 括号内的计算并保留 text
单词。这会产生一个包含 2 个元素的块,它很容易转换为 SET-PATH!。我使用 LOAD 而不是 TO-WORD 来处理连接到实际变量的一些 "magic",而普通单词转换不会这样做。但这只是一种变通方法 -- 不确定,并不总是解决问题的方法。
但是生成一个 SET-PATH!并不意味着 运行s。如果我说:
s: to-set-word "x"
probe type? s
没有设置字!被执行,它只是被生成。在这种情况下,存储在变量 s 中。但是如果我没有把它存储在一个变量中,评估产品就会被扔掉……如果我写1 + 1 print "hi"
,方式2就会被扔掉。要执行 SET-PATH!,您需要将它放在一个上下文中,它将被组合到源代码中并进行评估。
(注意:Ren-C 有一个 primitive called EVAL 可以即时执行此操作,例如 eval (quote x:) 10
会将 10 分配给 x。)
但是在 Red 中你需要做这样的事情:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
do probe compose [
(to-set-path compose [(load rejoin [namelist/:i "f"]) text])
to-string
(load namelist/:i)
]
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
现在您的外部 COMPOSE 正在构建一个 3 元素块,其中第一个元素是 SET-PATH!,第二个是 WORD!从字面上看,它只是将您的整数转换为字符串,第三个是 WORD!这将被评估为相关的整数。该块的DO将具有赋值效果。
我把你的 to-word namelist/:i
改成了 load namelist/:i
。同样,由于我提到的原因......单独的 TO-WORD 并没有放在 "binding".
我在那里留下了一个 PROBE,这样您就可以看到构建和执行的内容:
[var1f/text: to-string var1]
[var2f/text: to-string var2]
PROBE 是一个非常有用的工具,它输出它的参数,但也传递它。您可以在代码中的不同位置插入它,以便更好地了解正在发生的事情。
(注意:如果你想知道为什么我不建议编写一个仅适用于 SET-PATH 的窄 EVAL-2 辅助操作!,那是因为这样的东西存在于更好的名称。它被称为 SET。尝试 set (quote x:) 10
然后 print x
。事实上,这就是你实际想要做的事情的变体...... obj: make object! [a: 10]
然后 set (in obj 'a) 20
然后print obj/a
。正如我所说,有很多更好的方法来完成你正在做的事情,但我试图专注于按照你正在尝试的方式去做。)
第 1 步:重构
您的代码已重新格式化并添加了 print
(1) 条语句:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
print "process: start" ; (1)
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
print "process: end" ; (1)
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
当我在 控制台 中 运行 并按下 "Click" 时,它给出以下内容:
process: start
process: end
所以我知道至少按钮有效
第 2 步:使用 print
进行调试
现在我可以集中精力,在代码块内移动 print
:
process: [
repeat i length? namelist [
print (
to-set-path compose rejoin [
namelist/:i "f/text"
] (to-word namelist/:i)
)
]
]
我几乎立刻就能看出这里出了什么问题:
var1 ; expecting `var1f` here
var2 ;
第 3 步:我们需要更深入 probe
放在一边
现在,在我继续之前,请注意这段代码无法访问
视图块内的任何内容(因为它不起作用!)。
但这里的好处是你可以忽略它并稍后再回来。
您需要一种以编程方式访问 var1f/text
的方法
记住这一点,这里有一个更好的方式来表达这个问题:
步骤 3a:如何动态创建具有不同名称的 objects
并为其设置值?
var1f/text: 5
(给定步骤 2 中的代码)
现在,我遇到了一个难题。这可能最好作为一个不同的、更简单的问题来问。
我决定继续假设你完成了这个(还有另一个答案)
备注
在这一步中要带回家的重要事情是 datatype
红色视图 使用和你正在使用的是同一件事:红色 object
秒。
没有区别(都是简单人脸对象的实例)
第 4 步:大功告成!或者你是?
这样您就可以为您的工作创建所需的图形用户界面了!
对吗?
但是你问自己,这是最好的方法吗?
如果你想, or 怎么办?
- 你有read the official gui docs especially the part about view engine
- 您看过 vid and adding view
face
objects manually 的示例
- 您查看了 github 上的 sample code and small apps
的回购
- 您甚至尝试过旧的但稳定的 rebol2
但是你还是不明白?不要绝望,这很正常。
许多东西的名称在概念上与您在其他语言中所熟悉的名称相似,但在微妙的方式上有所不同,这往往使它们真正不同。
最后,很多东西比你想象的要简单,但更奇怪(有更深的含义)
tl;博士
- 将您的视图代码与其余部分分开,以便更容易调试
- 使用
print
、probe
和dump-face
调试
这并没有直接回答您的问题,但似乎解决了您面临的问题。它使用 face/extra
字段将字段关联到您的值列表:
namelist: [var1 var2]
var1: 5
var2: 10
process: function [][
foreach face lay/pane [
if find namelist face/extra [
face/text: form get to word! face/extra
]
]
]
lay: layout [
text "Values to appear here: "
field "a" extra 'var1
field "b" extra 'var2
button "Click" [process]
]
view lay
唯一的问题是:它应用 get
视图规范中设置的单词——它们需要与你正在处理的值处于相同的上下文中,并且——你可以得到一个 lit-word!
所以必须在得到之前改变它 to word!
。
另一种方法,如果你想在地图中包含你的值:
values: #(foo: 5 bar: 10)
process: function [container [object!]][
foreach face container/pane [
if find values face/extra [
face/text: form select values face/extra
]
]
]
view [
text "Values to appear here: "
field "a" extra 'foo
field "b" extra 'bar
button "Click" [process face/parent]
]
我在 namelist
中有字符串,它们对应于应用程序中的变量和字段名称。
函数应该从namelist中读取字符串,加上一个'f'得到field_names,然后把变量值放在相应的字段中。
我试过下面的代码,没有给出任何错误,但也不起作用:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
一般来说:将字符串转换为 WORD!s (例如 to-word "foo"
) 很容易。然而,神奇地创造这个词可能很难!引用绑定到 "the variable you meant"。这样做的巧妙原因与 没有范围 这一事实有关。参见:
Is there a overall explanation about definitional scoping in Rebol and Red
因此,无论如何,您尝试做的事情都会有点狡猾。有更好的方法。但是为了避免不问这个问题,我将解释这里发生了什么以及如何以您尝试的方式修复它。
更正后的版本仅用于教学目的。请换一种方式。
compose rejoin [namelist/:i "f/text"]
REJOIN 应用于块,并合并内容,结果类型 loosely 基于第一个元素。 (这是一个 questionable operation,但在 Rebol 代码中历来很流行。)
由于 namelist/:i
是一个字符串,您的 REJOIN 将生成一个字符串...并且该字符串最终将传递给 COMPOSE。但 COMPOSE 旨在应用于 BLOCK!s... 并在其中搜索带括号的组 inside,评估它们,同时保留其余代码。它是一种块模板系统,对其他类型的输入没有影响......所以你会得到相同的字符串。
TO-SET-PATH 因此被输入了一个字符串! (例如 "var1f/text")。我什至不知道路径转换接受字符串。我发现此操作的行为令人费解,因为它显然加载了字符串,然后使其成为长度为 1 SET-PATH!.
的奇异元素>> p: to-set-path "foo/bar"
== foo/bar: ;-- huh? really, did that work?
>> type? p
== set-path! ;-- ok, good, I guess.
>> length? p
== 1 ;-- wait, what?
>> type? first p
== path! ;-- a PATH! inside a SET-PATH!...?
>> length? first p
== 2
>> type? first first p
== word!
>> foo: 10
>> get first first p
== 10 ;-- well, at least it's bound
那可不是SET-PATH那种!你要;你想要一个 SET-PATH! 2个字!元素。转换块!设置路径!将是这样做的一种方式。
to-set-path compose [(load rejoin [namelist/:i "f"]) text]
现在我们看到 COMPOSE 被正确使用了,它将 运行 括号内的计算并保留 text
单词。这会产生一个包含 2 个元素的块,它很容易转换为 SET-PATH!。我使用 LOAD 而不是 TO-WORD 来处理连接到实际变量的一些 "magic",而普通单词转换不会这样做。但这只是一种变通方法 -- 不确定,并不总是解决问题的方法。
但是生成一个 SET-PATH!并不意味着 运行s。如果我说:
s: to-set-word "x"
probe type? s
没有设置字!被执行,它只是被生成。在这种情况下,存储在变量 s 中。但是如果我没有把它存储在一个变量中,评估产品就会被扔掉……如果我写1 + 1 print "hi"
,方式2就会被扔掉。要执行 SET-PATH!,您需要将它放在一个上下文中,它将被组合到源代码中并进行评估。
(注意:Ren-C 有一个 primitive called EVAL 可以即时执行此操作,例如 eval (quote x:) 10
会将 10 分配给 x。)
但是在 Red 中你需要做这样的事情:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
do probe compose [
(to-set-path compose [(load rejoin [namelist/:i "f"]) text])
to-string
(load namelist/:i)
]
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
现在您的外部 COMPOSE 正在构建一个 3 元素块,其中第一个元素是 SET-PATH!,第二个是 WORD!从字面上看,它只是将您的整数转换为字符串,第三个是 WORD!这将被评估为相关的整数。该块的DO将具有赋值效果。
我把你的 to-word namelist/:i
改成了 load namelist/:i
。同样,由于我提到的原因......单独的 TO-WORD 并没有放在 "binding".
我在那里留下了一个 PROBE,这样您就可以看到构建和执行的内容:
[var1f/text: to-string var1]
[var2f/text: to-string var2]
PROBE 是一个非常有用的工具,它输出它的参数,但也传递它。您可以在代码中的不同位置插入它,以便更好地了解正在发生的事情。
(注意:如果你想知道为什么我不建议编写一个仅适用于 SET-PATH 的窄 EVAL-2 辅助操作!,那是因为这样的东西存在于更好的名称。它被称为 SET。尝试 set (quote x:) 10
然后 print x
。事实上,这就是你实际想要做的事情的变体...... obj: make object! [a: 10]
然后 set (in obj 'a) 20
然后print obj/a
。正如我所说,有很多更好的方法来完成你正在做的事情,但我试图专注于按照你正在尝试的方式去做。)
第 1 步:重构
您的代码已重新格式化并添加了 print
(1) 条语句:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
print "process: start" ; (1)
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
print "process: end" ; (1)
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
当我在 控制台 中 运行 并按下 "Click" 时,它给出以下内容:
process: start
process: end
所以我知道至少按钮有效
第 2 步:使用 print
进行调试
现在我可以集中精力,在代码块内移动 print
:
process: [
repeat i length? namelist [
print (
to-set-path compose rejoin [
namelist/:i "f/text"
] (to-word namelist/:i)
)
]
]
我几乎立刻就能看出这里出了什么问题:
var1 ; expecting `var1f` here
var2 ;
第 3 步:我们需要更深入 probe
放在一边
现在,在我继续之前,请注意这段代码无法访问 视图块内的任何内容(因为它不起作用!)。 但这里的好处是你可以忽略它并稍后再回来。
您需要一种以编程方式访问 var1f/text
的方法
记住这一点,这里有一个更好的方式来表达这个问题:
步骤 3a:如何动态创建具有不同名称的 objects
并为其设置值?
var1f/text: 5
(给定步骤 2 中的代码)
现在,我遇到了一个难题。这可能最好作为一个不同的、更简单的问题来问。
我决定继续假设你完成了这个(还有另一个答案)
备注
在这一步中要带回家的重要事情是 datatype
红色视图 使用和你正在使用的是同一件事:红色 object
秒。
没有区别(都是简单人脸对象的实例)
第 4 步:大功告成!或者你是?
这样您就可以为您的工作创建所需的图形用户界面了! 对吗?
但是你问自己,这是最好的方法吗?
如果你想
- 你有read the official gui docs especially the part about view engine
- 您看过 vid and adding view
face
objects manually 的示例
- 您查看了 github 上的 sample code and small apps 的回购
- 您甚至尝试过旧的但稳定的 rebol2
但是你还是不明白?不要绝望,这很正常。 许多东西的名称在概念上与您在其他语言中所熟悉的名称相似,但在微妙的方式上有所不同,这往往使它们真正不同。 最后,很多东西比你想象的要简单,但更奇怪(有更深的含义)
tl;博士
- 将您的视图代码与其余部分分开,以便更容易调试
- 使用
print
、probe
和dump-face
调试
这并没有直接回答您的问题,但似乎解决了您面临的问题。它使用 face/extra
字段将字段关联到您的值列表:
namelist: [var1 var2]
var1: 5
var2: 10
process: function [][
foreach face lay/pane [
if find namelist face/extra [
face/text: form get to word! face/extra
]
]
]
lay: layout [
text "Values to appear here: "
field "a" extra 'var1
field "b" extra 'var2
button "Click" [process]
]
view lay
唯一的问题是:它应用 get
视图规范中设置的单词——它们需要与你正在处理的值处于相同的上下文中,并且——你可以得到一个 lit-word!
所以必须在得到之前改变它 to word!
。
另一种方法,如果你想在地图中包含你的值:
values: #(foo: 5 bar: 10)
process: function [container [object!]][
foreach face container/pane [
if find values face/extra [
face/text: form select values face/extra
]
]
]
view [
text "Values to appear here: "
field "a" extra 'foo
field "b" extra 'bar
button "Click" [process face/parent]
]