Red 语言中带有 to-word 和 to-path 的代码
code with to-word and to-path in Red language
我正在尝试使用 compose 通过单个函数创建 2 个面板:
make-panel: func [sentchar][
probe compose/deep [
text "N1:"
(to-set-word rejoin["fld1" sentchar ":"]) field ; TO BE NAMED fld1A and fld1B for 2 panels
text "N2: "
(to-set-word rejoin["fld1" sentchar ":"]) field ; TO BE NAMED fld2A and fld2B for 2 panels
text "Product: "
(to-set-word rejoin ["txt_out" sentchar ":"]) text ; TO BE NAMED txt_outA and txt_outB for 2 panels
button "Get product" [
x: to-path to-word (rejoin ["face/parent/pane/fld1" sentchar "/text"])
y: to-path to-word (rejoin ["face/parent/pane/fld2" sentchar "/text"])
(to-set-path (to-path rejoin ["face/parent/pane/txt_out" sentchar "text"] ))
form multiply get x get y ] ] ]
view compose [
(make-panel "A") return
(make-panel "B") return ]
但是,即使我尝试了不同的组合,我仍然收到关于目标词和目标路径的错误。问题出在哪里?
您的错误是试图创建一个带有“/”字符的单词。
>> to-word "foo/bar"
*** Syntax Error: invalid character in: "foo/bar"
*** Where: to
*** Stack: to-word
我的第二个倾向是你不应该使用字符串来组成值引用——如果没有其他的话你会失去绑定。可以尝试以下方法:
to path! compose [face parent pane (to word! rejoin ["fld2" sentchar]) text]
我的第一个倾向是你把它过于复杂化了,但这超出了你的问题范围。
更新:
我将尝试解决此代码中的其他一些问题:
命名
关于 make-panel
的注释——这是用词不当,因为您没有制作 panel
,只是将一些元素规格组合在一起。出于此答案的目的,我将使用名称 make-row
。此外,我永远不会喜欢 fld1
或 tout
(这是一个真实的词!)这样的名字,但会坚持下去。
动态命名选择器
正如我在上面提到的,与 Rebol/Red 中的字符串相比,从单词开始总是更好,单词在评估期间获取上下文——从字符串加载的单词则不会。例如:
make object! [
foo: "bar"
probe get first [foo] ; "bar"
probe get first load "[foo]" ; error
]
当您创建三个新词时,让我们明确地这样做:
make-row: function [row-id [string!]][
fld1: to word! rejoin ["fld1-" row-id]
fld2: to word! rejoin ["fld2-" row-id]
tout: to word! rejoin ["tout-" row-id] ; note that 'tout is an English word
...
]
从这里开始,我们可以开始在我们的规范中构建独特的参考。
make-row: func [row-id [string!] /local fld1 fld2 tout][
fld1: to word! rejoin ["fld1-" row-id]
fld2: to word! rejoin ["fld2-" row-id]
tout: to word! rejoin ["tout-" row-id]
compose/deep [
text "N1:"
(to set-word! fld1) field
text "N2:"
(to set-word! fld2) field
text "Product:"
(to set-word! tout) text
button "Get Product" [
...
]
return
]
]
现在我们通过这个按钮操作进入粘性区域:
x: to-path to-word (rejoin ["face/parent/pane/fld1" sentchar "/text"])
y: to-path to-word (rejoin ["face/parent/pane/fld2" sentchar "/text"])
(to-set-path (to-path rejoin ["face/parent/pane/tout" sentchar "text"] ))
form multiply get x get y ] ] ]
我认为可以在 pseudo-code 中表达您想要做的事情:
Product = text of product of N1 for this row * N2 for this row
此处代码中的主要错误是您将邻近引用与命名引用混合在一起。如果你检查 face/parent/pane
,它里面没有 fld1*
、fld2*
或 tout*
引用,它只是一块脸 objects。当您努力创建唯一的名称时,让我们暂时使用它。请记住,我们仍处于 compose/deep
操作的深处:
x: get in (fld1) 'data
y: get in (fld2) 'data
set in (tout) 'text form x * y
我们现在更简洁了,一切都应该正常工作(请注意,'data
为您提供了 'text
的加载值)。
邻近选择器
虽然我现在担心的是我们有很多新词,我们需要 x
和 y
。因此,让我们 return 了解接近度的概念。
当您查看组合视图规范时:
view probe compose [
(make-row "A")
(make-row "B")
]
您会看到您的主视图面将包含很多 children。要在您单击的按钮附近找到面孔,我们首先需要在面孔内找到按钮。让我们这样做:
button "Get Product" [
this: find face/parent/pane face
]
由于按钮前面有六个面孔,让我们转到这组的开头:
button "Get Product" [
this: skip find face/parent/pane face -6
]
现在我们可以根据邻近度进行计算:
button "Get Product" [
here: find face/parent/pane face
here/6/text: form here/2/data * here/4/data
]
轰!我们有相同的产品,只有一个词 here
而不是 rows-count * 3 + x + y
。太棒了!
因为我们没有生成任何额外的词,我们甚至不需要一个函数来生成我们的行,归结为以下几点:
row: [
text "N1:" field
text "N2: " field
text "Product: " text 100
button "Get product" [
; go back six faces from current face
here: skip find face/parent/pane face -6
here/6/text: form here/2/data * here/4/data
]
return
]
view compose [
(row)
(row)
]
组选择器
由于您的需求似乎很复杂,不能总是枚举您需要的字段,您可以使用extra
字段将字段组合在一起。我们可以通过使用块来包含 row-id
和 field-id
:
make-row: func [row-id][
compose/deep [
text "N1:" field extra [(row-id) "N1"]
text "N2: " field extra [(row-id) "N2"]
text "Product: " text 100 extra [(row-id) "Output"]
button "Get product" extra (row-id) [
...
]
return
]
]
view compose [
(make-row "A")
(make-row "B")
]
在按钮操作中,我们可以收集与该行关联的所有面孔:
faces: make map! collect [
foreach kid face/parent/pane [
if all [
block? kid/extra
face/extra = kid/extra/1
][
keep kid/extra/2
keep kid
]
]
]
这给了你一张漂亮的地图!所有相关的面孔和一个简单的计算:
faces/("Output")/text: form faces/("N1")/data * faces/("N2")/data
如果你只是打算将它用于产品,那么你甚至不需要收集:
product: 0
foreach kid face/parent/pane [
if all [
block? kid/extra
face/extra = kid/extra/1
][
product: product + kid/value
]
]
真正的挑战
make-panel: func [sentchar][
compose/deep [
text "N1:" (to-set-word rejoin['fld1 sentchar ]) field ; TO BE NAMED fld1A and fld1B for 2 panels
text "N2:" (to-set-word rejoin['fld2 sentchar ]) field ; TO BE NAMED fld2A and fld2B for 2 panels
text "Product: " (to-set-word rejoin ['tout sentchar]) text ; TO BE NAMED toutA and toutB for 2 panels
button "Get product" [
x: ( to-path reduce [ to-word rejoin ["fld1" sentchar] 'text ])
y: (to-path reduce [ to-word rejoin ["fld2" sentchar] 'text ])
(to-set-path reduce [to-word rejoin ["tout" sentchar] 'text]) form multiply load x load y
]
]
]
view v: compose [
(make-panel "A") return
(make-panel "B") return
]
当然不需要中间词x和y。但是这个你可以自己做。
我正在尝试使用 compose 通过单个函数创建 2 个面板:
make-panel: func [sentchar][
probe compose/deep [
text "N1:"
(to-set-word rejoin["fld1" sentchar ":"]) field ; TO BE NAMED fld1A and fld1B for 2 panels
text "N2: "
(to-set-word rejoin["fld1" sentchar ":"]) field ; TO BE NAMED fld2A and fld2B for 2 panels
text "Product: "
(to-set-word rejoin ["txt_out" sentchar ":"]) text ; TO BE NAMED txt_outA and txt_outB for 2 panels
button "Get product" [
x: to-path to-word (rejoin ["face/parent/pane/fld1" sentchar "/text"])
y: to-path to-word (rejoin ["face/parent/pane/fld2" sentchar "/text"])
(to-set-path (to-path rejoin ["face/parent/pane/txt_out" sentchar "text"] ))
form multiply get x get y ] ] ]
view compose [
(make-panel "A") return
(make-panel "B") return ]
但是,即使我尝试了不同的组合,我仍然收到关于目标词和目标路径的错误。问题出在哪里?
您的错误是试图创建一个带有“/”字符的单词。
>> to-word "foo/bar"
*** Syntax Error: invalid character in: "foo/bar"
*** Where: to
*** Stack: to-word
我的第二个倾向是你不应该使用字符串来组成值引用——如果没有其他的话你会失去绑定。可以尝试以下方法:
to path! compose [face parent pane (to word! rejoin ["fld2" sentchar]) text]
我的第一个倾向是你把它过于复杂化了,但这超出了你的问题范围。
更新:
我将尝试解决此代码中的其他一些问题:
命名
关于 make-panel
的注释——这是用词不当,因为您没有制作 panel
,只是将一些元素规格组合在一起。出于此答案的目的,我将使用名称 make-row
。此外,我永远不会喜欢 fld1
或 tout
(这是一个真实的词!)这样的名字,但会坚持下去。
动态命名选择器
正如我在上面提到的,与 Rebol/Red 中的字符串相比,从单词开始总是更好,单词在评估期间获取上下文——从字符串加载的单词则不会。例如:
make object! [
foo: "bar"
probe get first [foo] ; "bar"
probe get first load "[foo]" ; error
]
当您创建三个新词时,让我们明确地这样做:
make-row: function [row-id [string!]][
fld1: to word! rejoin ["fld1-" row-id]
fld2: to word! rejoin ["fld2-" row-id]
tout: to word! rejoin ["tout-" row-id] ; note that 'tout is an English word
...
]
从这里开始,我们可以开始在我们的规范中构建独特的参考。
make-row: func [row-id [string!] /local fld1 fld2 tout][
fld1: to word! rejoin ["fld1-" row-id]
fld2: to word! rejoin ["fld2-" row-id]
tout: to word! rejoin ["tout-" row-id]
compose/deep [
text "N1:"
(to set-word! fld1) field
text "N2:"
(to set-word! fld2) field
text "Product:"
(to set-word! tout) text
button "Get Product" [
...
]
return
]
]
现在我们通过这个按钮操作进入粘性区域:
x: to-path to-word (rejoin ["face/parent/pane/fld1" sentchar "/text"])
y: to-path to-word (rejoin ["face/parent/pane/fld2" sentchar "/text"])
(to-set-path (to-path rejoin ["face/parent/pane/tout" sentchar "text"] ))
form multiply get x get y ] ] ]
我认为可以在 pseudo-code 中表达您想要做的事情:
Product = text of product of N1 for this row * N2 for this row
此处代码中的主要错误是您将邻近引用与命名引用混合在一起。如果你检查 face/parent/pane
,它里面没有 fld1*
、fld2*
或 tout*
引用,它只是一块脸 objects。当您努力创建唯一的名称时,让我们暂时使用它。请记住,我们仍处于 compose/deep
操作的深处:
x: get in (fld1) 'data
y: get in (fld2) 'data
set in (tout) 'text form x * y
我们现在更简洁了,一切都应该正常工作(请注意,'data
为您提供了 'text
的加载值)。
邻近选择器
虽然我现在担心的是我们有很多新词,我们需要 x
和 y
。因此,让我们 return 了解接近度的概念。
当您查看组合视图规范时:
view probe compose [
(make-row "A")
(make-row "B")
]
您会看到您的主视图面将包含很多 children。要在您单击的按钮附近找到面孔,我们首先需要在面孔内找到按钮。让我们这样做:
button "Get Product" [
this: find face/parent/pane face
]
由于按钮前面有六个面孔,让我们转到这组的开头:
button "Get Product" [
this: skip find face/parent/pane face -6
]
现在我们可以根据邻近度进行计算:
button "Get Product" [
here: find face/parent/pane face
here/6/text: form here/2/data * here/4/data
]
轰!我们有相同的产品,只有一个词 here
而不是 rows-count * 3 + x + y
。太棒了!
因为我们没有生成任何额外的词,我们甚至不需要一个函数来生成我们的行,归结为以下几点:
row: [
text "N1:" field
text "N2: " field
text "Product: " text 100
button "Get product" [
; go back six faces from current face
here: skip find face/parent/pane face -6
here/6/text: form here/2/data * here/4/data
]
return
]
view compose [
(row)
(row)
]
组选择器
由于您的需求似乎很复杂,不能总是枚举您需要的字段,您可以使用extra
字段将字段组合在一起。我们可以通过使用块来包含 row-id
和 field-id
:
make-row: func [row-id][
compose/deep [
text "N1:" field extra [(row-id) "N1"]
text "N2: " field extra [(row-id) "N2"]
text "Product: " text 100 extra [(row-id) "Output"]
button "Get product" extra (row-id) [
...
]
return
]
]
view compose [
(make-row "A")
(make-row "B")
]
在按钮操作中,我们可以收集与该行关联的所有面孔:
faces: make map! collect [
foreach kid face/parent/pane [
if all [
block? kid/extra
face/extra = kid/extra/1
][
keep kid/extra/2
keep kid
]
]
]
这给了你一张漂亮的地图!所有相关的面孔和一个简单的计算:
faces/("Output")/text: form faces/("N1")/data * faces/("N2")/data
如果你只是打算将它用于产品,那么你甚至不需要收集:
product: 0
foreach kid face/parent/pane [
if all [
block? kid/extra
face/extra = kid/extra/1
][
product: product + kid/value
]
]
真正的挑战
make-panel: func [sentchar][
compose/deep [
text "N1:" (to-set-word rejoin['fld1 sentchar ]) field ; TO BE NAMED fld1A and fld1B for 2 panels
text "N2:" (to-set-word rejoin['fld2 sentchar ]) field ; TO BE NAMED fld2A and fld2B for 2 panels
text "Product: " (to-set-word rejoin ['tout sentchar]) text ; TO BE NAMED toutA and toutB for 2 panels
button "Get product" [
x: ( to-path reduce [ to-word rejoin ["fld1" sentchar] 'text ])
y: (to-path reduce [ to-word rejoin ["fld2" sentchar] 'text ])
(to-set-path reduce [to-word rejoin ["tout" sentchar] 'text]) form multiply load x load y
]
]
]
view v: compose [
(make-panel "A") return
(make-panel "B") return
]
当然不需要中间词x和y。但是这个你可以自己做。