Erlang "ping pong" concurrent programming example translated into SWI Prolog

Here’s how the pingpong program is written in Erlang:

-module(tut15).
-export([start/0, ping/2, pong/0]).

ping(0, Pong_PID) ->
    Pong_PID ! finished,
    io:format("ping finished");
ping(N, Pong_PID) ->
    Pong_PID ! {ping, self()},
    receive
        pong ->
            io:format("Ping received pong")
    end,
    ping(N - 1, Pong_PID).

pong() ->
    receive
        finished ->
            io:format("Pong finished");
        {ping, Ping_PID} ->
            io:format("Pong received ping"),
            Ping_PID ! pong,
            pong()
    end.

start() ->
    Pong_PID = spawn(tut15, pong, []),
    spawn(tut15, ping, [3, Pong_PID]).

Here’s how it looks in Web Prolog …

ping(0, Pong_Pid) :-
    Pong_Pid ! finished,
    io:format('Ping finished').
ping(N, Pong_Pid) :-
    self(Self),
    Pong_Pid ! ping(Self),
    receive({
        pong ->
            io:format('Ping received pong')
    }),
    N1 is N - 1,
    ping(N1, Pong_Pid).
    
pong :-
    receive({
        finished ->
            io:format('Pong finished');
        ping(Ping_Pid) ->
            io:format('Pong received ping'),
            Ping_Pid ! pong,
            pong
    }).

… except that when we start the game, we pass the node option so that the “pinger” and the “ponger” are running on different nodes and thus are playing pingpong over the network (which is something you can easily do in Erlang too):

start :-
    spawn(pong, Pong_Pid, [
        src_predicates([pong/0])
    ]),
    spawn(ping(3, Pong_Pid), _, [
        node('localhost:3020'),
        src_predicates([ping/2])
    ]).

And hey, why shouldn’t distributive programming be this easy!

With Web Prolog, I have always made it a priority to stay as close to Erlang as possible, and that’s how far I got.

As you can see, the receive is different and more high-level than what I implemented above by just calling thread_get_message/1, and there’s more to it than what’s shown here.

2 Likes