课程3 -- 传音筒、"name"和“process”
消息传递
The game of telephone is perfect to simulate message forwarding in rholang.
在前面的章节,我们学习了如何向祖母或披萨店发送消息。但是至今所有的接收方都通过将消息打印至标准输出,来告知已经接收到了。
现在让我们做一些更有意思的事情--类似孩子们的传话游戏那样传递消息。
telephone3.rho
你可以通过运行上面的代码来做实验。你可以修改你觉得合适的地方多运行几次。
练习
传话游戏很有趣,但有更多玩家参与会更好。请添加第三位明教Charlie的玩家。bob接收消息后将发送消息给Charlie,而不是简单打印至stdout。然后Charlie将它打印至屏幕上。多多益善!
The message never seems to get there correctly. I blame Bob.
练习
如果你曾经玩过电话游戏,你应该知道,消息极少能被正确地传递。Bob现在决定通过发送一条错误的消息。改写程序,使得Bob无论收到什么,都能传递不同的消息。
*这到底是啥?
Opposites attract
你注意到 @"Bob"!(message)中的? 在rholang中有两种类型, "names" 和 "processes"。同样也有可以在两者之间互相转化的方法。
"processes"可以是rholang中任何一个代码片段,例如我们的传话筒游戏,或者是披萨店订单程序。“process”可以是上百行的大程序,也可以只有几行。它们甚至可以是用于表示值的代码。下面是一些“process”的例子。
stdout!("Sup Rholang?") 一个常见的发送操作。
Nil 最小的“process”。如字面意思,它不做任何事。
for(msg <- @"phone"){Nil} 一个常见的接收操作,在消息到达时它不会做任何事。
"Hello World" 另一个不做任何事请的小“process”。被称为"基础术语"。 "names"可以被用于赋名通道以发送消息。在大多数编程语言中,"name"是完全独立的一样东西,它们本身就存在。但是在rholang中,"name"来自"引用process",即将@标签放在“process”之前,即可得到一个"name"。下面是"name"的一些例子。
@"Hello World" 通过引用基础术语"Hello World"来创建。
@nil 最小的“name”。通过引用最小的“process”来创建。
@(@"Alice"!("I like rholang, pass it on."))
通过引用来自传话筒游戏的"process"来创建。
关于*的一切
What kind of name is that!? Did your parents just name you after some computer code?
通过用@符号来标记“process”,我们可以将“process”打包以创建一些“name”。我们也可以通过使用*标记“name”,从而将“name”转变为“process”。
在rholang中,我们需要记住的是发送“process”和接收“name”。这很重要,因此我再次强调。你总是发送一个“process”,在另一端接收一个“name”。
Aice通过for(message <- @"Alice")接收我们的消息,所以, message 变成了一个“name”。当她之后发送给Bob时,她不得不发送“process”,所以她要用@"Bob"!(message)使用将message转变回一个“process”。
小测验
我们发送什么?
processes
names
我们接收什么?
processes
names
@"registration"是什么?
process
name
非法语法
Nil是什么?
process
name
非法语法
@Nil是什么?
process
name
非法语法
@@Nil是什么?
process
name
非法语法
*importantData 是一个“process”, 那么importantData是什么?
process
name
非法语法
下面哪一个与"BobsPhone"等价?
*@"BobsPhone"
@"BobsPhone"
*"BobsPhone"
@*BobsPhone
stdout!("BobsPhone")
练习
This telephone game has a fork
不像之前的线性传话游戏那样,每个玩家将信息传递给下一位,我么来为游戏添加一个分支。现在,Bob与先前一样将发送消息给Charlie,但同时也会发送给Elise。
每个分支的长度由你定,但在每个分支的最后都得将消息打印至标准输出。
课程4 -- 持续发送与窥探
为什么要重复发送?
This radio navigation aid helps airplanes navigate by broadcasting the same message over and over
我们的披萨和咖啡店都可以在同一个复用通道中接收消息。我们使用一个持续的for (msg <= chan){...}或者一个合约contract chan(msg){...}来达成这一目的。
空中交通管制塔楼可能会乐于做刚好相反的事——不停地发送相同的消息。塔楼中的控制者希望记录同时包含天气和跑道信息的消息,并且提供给所有需要的飞行员。类似披萨店, 他们很繁忙,不会费力地在每次飞行员需要时都不停地发送信息。
持续发送的语法
控制塔需要在代码上做较小的调整,以使得发送操作能够持续。他们会使用!!而非单个!。
persistentSend.rho
请自行确认一下,原先发送的消息是否仍然在元组空间内。
练习
注意上述代码,第二名飞行员同样能够接收到信息。发送仍在持续。
对了,你注意到了吗?当我们实际上并不使用stdout时,我们不需要new stdout(...) in {}
for (x <- y) {Nil} | y!!(Nil)中有多少次通信事件发生?
1
很多次
0
二次检查消息
正如我们刚才展示的,持续性发送和接收非常有用。但是,普通的发送和接收也同样足够好了。设想这样的场景:我将一个字母发送给祖母,她接收到了这个消息。
grandma.rho
现在我们设想:我想要二次检查我是否给她发送了正确的时间。我可以简单地取出这条消息,但这样一来她就没法读取这个消息了。
练习
依据你所知道的,你可以通过获取这个消息,自行检查它,再将它发送回旧的通道,以达到我们的目的。
请自行尝试上面的方案。答案已列在下面。
for (x <= y) {Nil} | y!!(Nil)会产生多少个通信事件?
1
很多个
0
答案
grandmaCheck.rho
窥探语法
Maybe I'll just peak at Grandma's letter through the envelope.
rholang以后会为观察通道内变量提供一个特殊的语法。目前我们还不能使用它,但是下面会展示给你看这个语法的用法。我们将使用<!操作符来"窥探"一个通道内的消息。
peek.rho
如果你使用过excel的宏,或者excel,你应该对如何在不取出数据的情况下访问它感到非常熟悉。把它当做for (value <! A1) { ... }。
下列哪一个语法是用于窥探一个消息的?
for (x <! y){...}
for (x <= y){...}
x!!(y)
for (x <! y) {Nil} | y!!(Nil)会产生多少个通信事件?
1
许多
0
课程5 -- Join操作
多数据源
In general, the winner of this pushup competition can't be determined until both participants are finished.
有时候仅当从两个以上不同的数据源获取数据后,才会开始计算。例如,在你得知了你的彩票号码和中奖号码之前,你无法知道你是否赢得大奖。在你知道购买物品价格和购买总额之前,你无法进行购买。在你知道每个参赛者做了多少个俯卧撑前,你无法知道谁赢得俯卧撑比赛。
rholang提供了Join操作,来应对这种情况。使用;符号来执行一次Join操作。
for (p1Pushups <- @"player1"; p2Pushups <- @"player2") { @"stdout"!("The winner is...") }
火箭发射
一家太空探索公司想要确保,仅当两个航空工程师,Alice和Bob,都下达了发射命令后,他们的火箭才会发射。例如,Bob将通过发送BobLaunch!("launch")来下达命令。当两位工程师都下达了命令,那么火箭便可以发射。
练习
思考一下,使用我们刚提到的Join操作符,应该怎么写这个代码呢?
错误的方式
下面的例子中,其中一人先收到发射指令,并尝试处理火箭发射问题,然后再轮到另一个人。
launchBad.rho
问题在于,当Alice批准发射,而Bob还没有,Alice应该能够更改她的指令,但在此例中她不行。设想一下,如果她突然发觉火箭有一个问题,或者收到了一些不好的消息,想要停止发射。
No use in grabbing just one set of mail. Might as well wait until the second set
当使用Join时,她依然可以更改她的决定,因为for只会在双方的消息都进入通道并准备好后,才会开始取出双方的消息。
发射的解决方案
launch.rho
下列哪一段代码是Alice所需,用以撤销发射命令的?
@"AliceCancel"!("cancelZ")
@"AliceLaunch"!("cancel")
for (x <- @"AliceLaunch"){Nil}
Join的概念起初是在哲学家进餐问题中被提出,并且在这篇简短的rholang教程中(更详细的解释)[developer.rchain.coop/tutorial/#d…"]。
在for (x <- y; a <- b){ Nil }中, 应该优先向哪一个通道发送消息?
y
b
无所谓
同时被发送
在for (x <- y; a <- b){ Nil }中, 哪一条消息被优先取出?
x
a
无所谓
会被同时取出
练习
有一个比赛,两名选手将各自在各自的通道发送消息。谁第一个发送了消息,谁就输掉比 赛,第二个发送消息的人获胜。你的任务是写一段代码告诉我们谁赢了。参赛选手应按如下方式发送消息。
P1!("Send any message") P2!("Hope I win")
在这场需要靠耐心获胜竞赛这一例子中,我们不使用求并运算,因为我们在意哪个选手先行动。希望你没有陷入我的陷阱中;)
patienceSolution.rho
正如注释所说,你应该使用REPL模式运行上面的代码,然后用两种不同的顺序来发送的消息确保两个选手都获胜一次。另一个方案如下所示,让一个玩家去通知另一个玩家何时执行。我们将在下一节继续研究这种方法。
P1First.rho
在上面我们写的代码中,为什么可能出现没有人赢得这场耐心比赛?
因为两名选手可以同时发送消息
选手们在错误的通道发送消息
第一个块接收P2,而第二个块接收P1,所以代码并不能保证游戏完成 |