Very simple example of Rholang with Set as the state
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object rholang { | |
/** | |
* This interface represents terms in our Simple Rholang language. | |
* Everything is a process. | |
*/ | |
trait Process | |
/** | |
* AST of our Simple Rholang language. It's private and accessible only | |
* inside this object. The only way to change the state (Set[Process]) is to | |
* call defined operations (nil, par, send, receive). | |
*/ | |
private final case class Par(s: Set[Process] = Set()) extends Process | |
private final case class Send(name: String) extends Process | |
private final case class Receive(name: String) extends Process | |
/** | |
* `nil` and `par` are Monoid operations (empty, combine). | |
* | |
* All terms (processes) are collected in a Set defined in Par(Set[Process]). | |
*/ | |
def nil: Process = Par(s = Set()) | |
def par(p1: Process, p2: Process = nil): Process = (p1, p2) match { | |
// Combine states from both Par's | |
// This rule also "erase" `nil` from both sides of Par | |
// nil | p == p == p | nil | |
case (Par(s1), Par(s2)) => Par(s1 ++ s2) | |
// Next two cases flatten nested Par's | |
// Par(Set(Par(Send(A)))) => Par(Set(Send(A))) | |
case (Par(s1), p2) => Par(s1 + p2) | |
case (p1, Par(s2)) => Par(s2 + p1) | |
// All other cases just collect in a Set | |
case (p1, p2) => Par(Set(p1, p2)) | |
} | |
/** | |
* `send` and `receive` represent basic operations. | |
*/ | |
def send(name: String): Process = par(Send(name)) | |
def receive(name: String): Process = par(Receive(name)) | |
/** | |
* Reductions of our super Simple Rholang language. | |
* When matching Send/Receive are found they are erased. | |
*/ | |
def eval(proc: Process): Process = | |
proc match { | |
case Par(state) => | |
val procs = state.foldLeft(Set[Process]()) { | |
// Reduction of Send if matches Receive | |
case (acc, send @ Send(name)) => | |
if (state.contains(Receive(name))) acc | |
else if (name.startsWith("OUT")) { | |
// If special name do something | |
println(name) | |
acc | |
} else acc + send | |
// Reduction of Receive if matches Send | |
case (acc, rec @ Receive(name)) => | |
if (state.contains(Send(name))) acc | |
else acc + rec | |
// For all other combinations we do nothing | |
case (acc, p) => acc + p | |
} | |
Par(procs) | |
case p => p | |
} | |
} | |
import rholang._ | |
// Defines | as `par` for nicer syntax | |
implicit class syntaxRholang(private val p1: Process) extends AnyVal { | |
def |(p2: Process): Process = par(p1, p2) | |
} | |
/** | |
* Our first Simple Rholang program. | |
*/ | |
val prog1: Process = { | |
val p1 = send("A") | |
val p2 = send("B") | |
val p3 = receive("B") | |
val p4 = send("B") | |
val p5 = send("OUT: Special channel!") | |
val p6 = receive("C") | |
p1 | p2 | p3 | p4 | p5 | p6 | nil | |
} | |
// prog1: rholang.Process = Par(Set(Send(B), Receive(B), Receive(C), Send(OUT: Special channel!), Send(A))) | |
val prog2 = send("A") | |
val prog3 = receive("B") | send("A") | |
// Structural equivalence | |
val prog4 = send("A") | nil | |
val prog5 = nil | send("A") | |
val progEqual_2_4_5 = (prog2 == prog4, prog4 == prog5) | |
val prog7 = send("A") | send("A") | |
/** | |
* Evaluate the program and get remaining processes (state inside Par). | |
*/ | |
val res = eval(prog1) | |
// OUT: Special channel! | |
// res: Process = Par(Set(Receive(C), Send(A))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment