如何将这个示例代码从Go转换为Erlang?

huangapple go评论85阅读模式
英文:

How to convert this example code from Go to Erlang

问题

我想我可以一举两得,通过将以下示例代码(取自http://blog.smartbear.com/programming/an-introduction-to-the-go-language-boldly-going-where-no-man-has-ever-gone-before/)从Go语言转换为Erlang来学习一些Go和Erlang:

package main

import (
	"fmt"
	"time"
)

type Ball struct{ hits int }

func main() {
	table := make(chan *Ball)
	go player("ping", table)
	go player("pong", table)
	table <- new(Ball) // game on; toss the ball
	time.Sleep(1 * time.Second)
	<-table // game over; grab the ball
}

func player(name string, table chan *Ball) {
	for {
		ball := <-table
		ball.hits++
		fmt.Println(name, ball.hits)
		time.Sleep(100 * time.Millisecond)
		table <- ball
	}
}

然而,我失败了。该代码基本上创建了一个共享计数器(球),并在两个goroutine(玩家)之间来回发送它。到目前为止还好。但是在Erlang中如何做类似的事情呢?我的问题是:

  • 如何在Erlang中创建一个计数器?Erlang似乎不允许在设置后更改变量的值。

  • 如何在两个Erlang进程之间共享这样的计数器?

英文:

I thought I could kill two birds with one stone and teach myself a little Go and Erlang by converting the following example code (taken from http://blog.smartbear.com/programming/an-introduction-to-the-go-language-boldly-going-where-no-man-has-ever-gone-before/) from Go to Erlang:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

type Ball struct{ hits int }

func main() {
	table := make(chan *Ball)
	go player(&quot;ping&quot;, table)
	go player(&quot;pong&quot;, table)
	table &lt;- new(Ball) // game on; toss the ball
	time.Sleep(1 * time.Second)
	&lt;-table // game over; grab the ball
}

func player(name string, table chan *Ball) {
	for {
		ball := &lt;-table
		ball.hits++
		fmt.Println(name, ball.hits)
		time.Sleep(100 * time.Millisecond)
		table &lt;- ball
	}
}

However I failed. The code basically creates a shared counter (the ball) and sends it back and forth between the two goroutines (the players). So far so good. But how do I do something similar in Erlang? My problems were:

  • How to create a counter in Erlang? Erlang doesn't seem to allow to
    change the value of a variable once it is set.
  • How to share such a counter between two erlang processes?

答案1

得分: 3

在Erlang中,变量是不可变的,这意味着在一个函数的求值过程中,变量要么未绑定,要么被设置为一个不可改变的值。但是你可以使用前一个值构建一个新值,并以递归的方式调用相同的函数。该值通常存储在一个称为状态的变量中,在接收到消息时进行修改。这是服务器的基本行为。

在你的例子中,你实际上不需要一个变量来保存计数器,因为这个值将在两个玩家之间交换。它可以包含在它们之间交换的消息中,例如一个元组{count,V}。

在两个进程之间通信的唯一方法是通过消息传递。最简单的语法是 Pid ! Message,其中 Pid 是接收者的进程ID,Message 是消息本身(如果进程已注册,Pid 可以被一个名称替代)。

使用这个语法,你可以编写以下代码:

-module(pingpong).
-export([start/0,player/1,stop/1]).

player(Name) ->
    receive
        {count,From,Val} ->
            io:format("~p received the ball for the ~p th exchange~n",[Name,Val]),
            ok = timer:sleep(500),
            From ! {count,self(),Val+1},
            player(Name);
        {start,To} ->
            io:format("~p start the exchange~n",[Name]),
            To ! {count,self(),1},
            player(Name);
         stop -> gameover
     end.

start() ->
    Ping = spawn(?MODULE,player,[ping]),
    Pong = spawn(?MODULE,player,[pong]),
    Ping ! {start,Pong},
    {Ping,Pong}.

stop(P1) -> P1 ! stop.

在Shell中执行以下操作:

1> c(pingpong).
{ok,pingpong}
2> {P1,P2} = pingpong:start().
ping start the exchange
pong received the ball for the 1 th exchange
{<0.39.0>,<0.40.0>}
ping received the ball for the 2 th exchange
pong received the ball for the 3 th exchange
ping received the ball for the 4 th exchange
pong received the ball for the 5 th exchange
ping received the ball for the 6 th exchange
pong received the ball for the 7 th exchange
ping received the ball for the 8 th exchange
pong received the ball for the 9 th exchange
ping received the ball for the 10 th exchange
pong received the ball for the 11 th exchange
ping received the ball for the 12 th exchange
pong received the ball for the 13 th exchange
ping received the ball for the 14 th exchange
pong received the ball for the 15 th exchange
ping received the ball for the 16 th exchange
pong received the ball for the 17 th exchange
ping received the ball for the 18 th exchange
pong received the ball for the 19 th exchange
ping received the ball for the 20 th exchange
pong received the ball for the 21 th exchange
ping received the ball for the 22 th exchange
pong received the ball for the 23 th exchange
ping received the ball for the 24 th exchange
3> pingpong:stop(P1).
stop
4> pingpong:stop(P2).
stop
5>

希望这可以帮助到你!

英文:

A variable is not mutable in erlang, that means that during the evaluation of one function, the variable is either unbound, either set to a value that cannot change. But you can recall the same function with a new value build from the former one, recursively. The value is stored in a variable generally called the state, and it is modified when a message is received. This is the basic behaviour of a server.

In your example you don't really need a variable to contain the counter since this value will be exchange between the 2 players. I can be contained in the message exchanged between them for example in a tuple {count,V}.

The only way to communicate between 2 processes is message passing. The simplest syntax is Pid ! Message, where Pid is the process ID if the receiver, and Message , well the message :o) (Pid can be replaced by a name if the process is registered).

with this you can write:

-module(pingpong).
-export([start/0,player/1,stop/1]).

player(Name) -&gt;
    receive
        {count,From,Val} -&gt; 
            io:format(&quot;~p received the ball for the ~p th exchange~n&quot;,[Name,Val]),
            ok = timer:sleep(500),
            From ! {count,self(),Val+1},
            player(Name);
        {start,To} -&gt;
            io:format(&quot;~p start the exchange~n&quot;,[Name]),
            To ! {count,self(),1},
            player(Name);
         stop -&gt; gameover
     end.

start() -&gt;
    Ping = spawn(?MODULE,player,[ping]),
    Pong = spawn(?MODULE,player,[pong]),
    Ping ! {start,Pong},
    {Ping,Pong}.

stop(P1) -&gt; P1 ! stop. 

in the shell:

1&gt; c(pingpong).
{ok,pingpong}
2&gt; {P1,P2} = pingpong:start().
ping start the exchange
pong received the ball for the 1 th exchange
{&lt;0.39.0&gt;,&lt;0.40.0&gt;}
ping received the ball for the 2 th exchange
pong received the ball for the 3 th exchange
ping received the ball for the 4 th exchange
pong received the ball for the 5 th exchange
ping received the ball for the 6 th exchange
pong received the ball for the 7 th exchange
ping received the ball for the 8 th exchange
pong received the ball for the 9 th exchange
ping received the ball for the 10 th exchange
pong received the ball for the 11 th exchange
ping received the ball for the 12 th exchange
pong received the ball for the 13 th exchange
ping received the ball for the 14 th exchange
pong received the ball for the 15 th exchange
ping received the ball for the 16 th exchange
pong received the ball for the 17 th exchange
ping received the ball for the 18 th exchange
pong received the ball for the 19 th exchange
ping received the ball for the 20 th exchange
pong received the ball for the 21 th exchange
ping received the ball for the 22 th exchange
pong received the ball for the 23 th exchange
ping received the ball for the 24 th exchange
3&gt; pingpong:stop(P1).
stop
4&gt; pingpong:stop(P2).
stop
5&gt;

huangapple
  • 本文由 发表于 2014年10月11日 23:01:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/26316005.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定