{"id":208,"date":"2006-11-10T12:48:26","date_gmt":"2006-11-10T12:48:26","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2006\/11\/10\/friday-pathological-programming-bad-actors-in-cruise\/"},"modified":"2006-11-10T12:48:26","modified_gmt":"2006-11-10T12:48:26","slug":"friday-pathological-programming-bad-actors-in-cruise","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2006\/11\/10\/friday-pathological-programming-bad-actors-in-cruise\/","title":{"rendered":"Friday Pathological Programming: Bad Actors in Cruise"},"content":{"rendered":"<p>Today&#8217;s pathological language is a bit of a treat for me. I&#8217;m going to show you a twisted,<br \/>\nannoying, and thoroughly pointless language that *I* created.<br \/>\nThe language is based on a model of computation called [Actors](http:\/\/en.wikipedia.org\/wiki\/Actor_model), which was originally proposed by Professor Gul Agha of UIUC. There&#8217;ve been some really nice languages built using ideas from Actors, but this is *not* one of them. And that&#8217;s exactly where the name comes from. What name comes to mind when you think of *really bad* actors with delusions of adequacy? For me, it&#8217;s &#8220;Cruise&#8221;.<br \/>\nYou can get the code for Cruise on Google code, project &#8220;Cruise&#8221;, or you can grab a bundle containing the code, and a compiled binary in a jarfile [here](http:\/\/scienceblogs.com\/goodmath\/upload\/2006\/11\/cruise.zip). To run it, just &#8220;java -jar Cruise.jar cruse-program-file&#8221;. Just so you know, the code *sucks*. It&#8217;s something I threw together in my spare time, so it&#8217;s sloppy, overcomplicated, probably buggy, and slow as a snail on tranquilizers.<\/p>\n<p><!--more--><br \/>\nQuick overview of the actor model<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\nActors are a theoretical model of computation, which is designed to describe completely<br \/>\nasynchronous parallel computation. Doing things totally asynchronously is very strange, and very counter-intuitive. But the fact of the matter is, in real distributed systems, everything *is* fundamentally asynchronous, so being able to describe distributed systems in terms of a simple, analyzable model is a good thing.<br \/>\nAccording to the actor model, a computation is described by a collection of things called, what else, actors. An actor has a *mailbox*, and a *behavior*. The mailbox is a uniquely named place where messages sent to an actor can be queued; the behavior is a definition of how the actor is going to process a message from its mailbox. The behavior gets to look at the message, and based on its<br \/>\ncontents, it can do three kinds of things:<br \/>\n1. Create other actors.<br \/>\n2. Send messages to other actors whose mailbox it knows.<br \/>\n3. Specify a new behavior for the actor to use to process its next message.<br \/>\nYou can do pretty much anything you need to do in computations with that basic mechanism. The catch<br \/>\nis, as I said, it&#8217;s all asynchronous. So, for example, if you want to write an actor that adds two<br \/>\nnumbers, you *can&#8217;t* do it by what you&#8217;d normally think of as a subroutine call. In a lot of ways, it *looks* like a method call in something like Smalltalk: one actor (object) sends a message to another actor, and in response, the receiver takes some action specified by them message.<br \/>\nBut subroutines and methods are synchronous, and *nothing* in actors is synchronous. In an object-oriented language, when you send a message, you stop and wait until the receiver of the message is done with it. In Actors, it doesn&#8217;t work that way: you send a message, and it&#8217;s sent, over and done with. You don&#8217;t wait for anything; you&#8217;re done.  If you want a reply, you need to send the the other actor a reference to your mailbox, and make sure that your behavior knows what to do when the reply comes in.<br \/>\nIt ends up looking something like the continuation passing form of a functional programming language: to do a subroutine-like operation, you need to pass an extra parameter to the subroutine invocation; that extra parameter is the *intended receiver* of the result.<br \/>\nYou&#8217;ll see some examples of this when we get to some code.<br \/>\nTuples &#8211; A Really Ugly Way of Handling Data<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\nCruise has a strange data model. The idea behind it is to make it easy to build actor behaviors around the idea of pattern matching. The easiest\/stupidest way of doing this is to make all data consist of tagged tuples. A tagged tuple consists of a tag name (an identifier starting with an uppercase letter), and a list of values enclosed in the tuple. The values inside of a tuple can be either other tuples, or actor names (identifiers starting with lower-case letters).<br \/>\nSo, for example, `Foo(Bar(), adder)` is a tuple. The tag is &#8220;`Foo`&#8221;. It&#8217;s contents are another tuple, &#8220;`Bar()`&#8221;, and an actor name, &#8220;`adder`&#8221;.<br \/>\nSince tuples and actors are the only things that exist, we need to construct all other types<br \/>\nof values from some combination of tuples and actors. To do math, we can use tuples to build up Peano numbers. The tuple &#8220;`Z()`&#8221; is zero; &#8220;`I(n)`&#8221; is the number `n+1&#8242;. So, for example, 3 is &#8220;`I(I(I(Z())))`&#8221;.<br \/>\nThe only way to decompose tuples is through pattern matching in messages. In an actor behavior. message handlers specify a *tuple pattern*, which is a tuple where some positions may be filled by{em unbound} variables. When a tuple is matched against a pattern, the variables in the pattern are bound to the values of the corresponding elements of the tuple.<br \/>\nA few examples:<br \/>\n* matching `I(I(I(Z())))` with `I($x)` will succeed with `$x` bound to `I(I(Z))`.<br \/>\n* matching `Cons(X(),Cons(Y(),Cons(Z,Nil())))` with `Cons($x,$y)` will succeed with<br \/>\n$x bound to `X()`, and $y bound to `Cons(Y(),Cons(Z(),Nil()))`.<br \/>\n* matching `Cons(X(),Cons(Y(),Cons(Z(),Nil())))` with `Cons($x, Cons(Y(), Cons($y, Nil())))` will succeed with `$x` bound to `X()`, and `$y` bound to `Z()`.<br \/>\nCruise &#8211; the Language of Bad Actors<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\nInstead of my rambling on even more, let&#8217;s take a look at some Cruise programs. We&#8217;ll<br \/>\nstart off with Hello World, sort of.<br \/>\nactor !Hello {<br \/>\nbehavior :Main() {<br \/>\non Go() { send Hello(World()) to out }<br \/>\n}<br \/>\ninitial :Main<br \/>\n}<br \/>\ninstantiate !Hello() as hello<br \/>\nsend Go() to hello<br \/>\nThis declares an actor type &#8220;!Hello&#8221;; it&#8217;s got one behavior with no parameters. It only knows<br \/>\nhow to handle one message, &#8220;Go()&#8221;. When it receives go, it sends a hello world tuple to the actor named &#8220;out&#8221;, which is a built-in that just prints whatever is sent to it.<br \/>\nLet&#8217;s be a bit more interesting, and try something using integers. Here&#8217;s some code to do<br \/>\na greater than comparison:<br \/>\nactor !GreaterThan {<br \/>\nbehavior :Compare() {<br \/>\non GT(Z(),Z(), $action, $iftrue, $iffalse) { send $action to $iffalse }<br \/>\non GT(Z(), I($x), $action, $iftrue, $iffalse) { send $action to $iffalse }<br \/>\non GT(I($x), Z(), $action, $iftrue, $iffalse) { send $action to $iftrue }<br \/>\non GT(I($x), I($y), $action, $iftrue, $iffalse) { send GT($x,$y,$action,$iftrue,$iffalse) to $self }<br \/>\n}<br \/>\ninitial :Compare<br \/>\n}<br \/>\nactor !True {<br \/>\nbehavior :True() {<br \/>\non Result() { send True() to out}<br \/>\n}<br \/>\ninitial :True<br \/>\n}<br \/>\nactor !False {<br \/>\nbehavior :False() {<br \/>\non Result() { send False() to out}<br \/>\n}<br \/>\ninitial :False<br \/>\n}<br \/>\ninstantiate !True() as true<br \/>\ninstantiate !False() as false<br \/>\ninstantiate !GreaterThan() as greater<br \/>\nsend GT(I(I(Z())), I(Z()), Result(), true, false) to greater<br \/>\nsend GT(I(I(Z())), I(I(I(Z()))), Result(), true, false) to greater<br \/>\nsend GT(I(I(Z())), I(I(Z())), Result(), true, false) to greater<br \/>\nThis is typical of how you do &#8220;control flow&#8221; in Cruise: you set up different actors<br \/>\nfor each branch, and pass those actors names to the test; one of them will receive<br \/>\na message to continue the execution.<br \/>\nWhat about multiple behaviors? Here&#8217;s a trivial example of a flip-flop:<br \/>\nactor !FlipFlop {<br \/>\nbehavior :Flip() {<br \/>\non Ping($x) { send Flip($x) to out<br \/>\nadopt :Flop() }<br \/>\non Pong($x) { send Flip($x) to out}<br \/>\n}<br \/>\nbehavior :Flop() {<br \/>\non Ping($x) { send Flop($x) to out }<br \/>\non Pong($x) { send Flop($x) to out<br \/>\nadopt :Flip() }<br \/>\n}<br \/>\ninitial :Flip<br \/>\n}<br \/>\ninstantiate !FlipFlop() as ff<br \/>\nsend Ping(I(I(Z()))) to ff<br \/>\nsend Ping(I(I(Z()))) to ff<br \/>\nsend Ping(I(I(Z()))) to ff<br \/>\nsend Ping(I(I(Z()))) to ff<br \/>\nsend Pong(I(I(Z()))) to ff<br \/>\nsend Pong(I(I(Z()))) to ff<br \/>\nsend Pong(I(I(Z()))) to ff<br \/>\nsend Pong(I(I(Z()))) to ff<br \/>\nIf the actor is in the &#8220;:Flip&#8221; behavior, then when it gets a &#8220;Ping&#8221;, it sends &#8220;Flip&#8221; to out, and switches behavior to flop. If it gets point, it just sents &#8220;Flip&#8221; to out, and stays in &#8220;:Flip&#8221;.<br \/>\nThe &#8220;:Flop&#8221; behavior is pretty much the same idea, accept that it switches behaviors on &#8220;Pong&#8221;.<br \/>\nAn example of how behavior changing can actually be useful is implementing settable variables:<br \/>\nactor !Var {<br \/>\nbehavior :Undefined() {<br \/>\non Set($v) { adopt :Val($v) }<br \/>\non Get($target) { send Undefined() to $target }<br \/>\non Unset() { }<br \/>\n}<br \/>\nbehavior :Val($val) {<br \/>\non Set($v) { adopt :Val($v) }<br \/>\non Get($target) { send $val to $target }<br \/>\non Unset() { adopt :Undefined() }<br \/>\n}<br \/>\ninitial :Undefined<br \/>\n}<br \/>\ninstantiate !Var() as v<br \/>\nsend Get(out) to v<br \/>\nsend Set(I(I(I(Z())))) to v<br \/>\nsend Get(out) to v<br \/>\nTwo more programs, and I&#8217;ll stop torturing you. First, a simple adder:<br \/>\nactor !Adder {<br \/>\nbehavior :Add() {<br \/>\non Plus(Z(),$x, $target) { send $x to $target }<br \/>\non Plus(I($x), $y, $target) { send Plus($x,I($y), $target) to $self }<br \/>\n}<br \/>\ninitial :Add<br \/>\n}<br \/>\nactor !Done {<br \/>\nbehavior :Done() {<br \/>\non Result($x) { send Result($x) to out }<br \/>\n}<br \/>\ninitial :Done<br \/>\n}<br \/>\ninstantiate !Adder() as adder<br \/>\ninstantiate !Done() as done<br \/>\nsend Plus(I(I(I(Z()))),I(I(Z())), out) to adder<br \/>\nPretty straightforward &#8211; the only interesting thing about it is the way that it sends the result of invoking add to a continuation actor.<br \/>\nNow, let&#8217;s use an addition actor to implement a multiplier actor. This shows off some interesting techniques, like carrying auxiliary values that will be needed by the continuation. It also shows<br \/>\nyou that I cheated, and added integers to the parser; they&#8217;re translated into the peano-tuples<br \/>\nby the parser.<br \/>\nactor !Adder {<br \/>\nbehavior :Add() {<br \/>\non Plus(Z(),$x, $misc, $target) { send Sum($x, $misc) to $target }<br \/>\non Plus(I($x), $y, $misc, $target) {<br \/>\nsend Plus($x,I($y), $misc, $target) to $self<br \/>\n}<br \/>\n}<br \/>\ninitial :Add<br \/>\n}<br \/>\nactor !Multiplier {<br \/>\nbehavior :Mult() {<br \/>\non Mult(I($x), $y, $sum, $misc, $target) {<br \/>\nsend Plus($y, $sum, MultMisc($x, $y, $misc, $target), $self) to adder<br \/>\n}<br \/>\non Sum($sum, MultMisc(Z(), $y, $misc, $target)) {<br \/>\nsend Product($sum, $misc) to $target<br \/>\n}<br \/>\non Sum($sum, MultMisc($x, $y, $misc, $target)) {<br \/>\nsend Mult($x, $y, $sum, $misc, $target) to $self<br \/>\n}<br \/>\n}<br \/>\ninitial :Mult<br \/>\n}<br \/>\ninstantiate !Adder() as adder<br \/>\ninstantiate !Multiplier() as multiplier<br \/>\nsend Mult(32, 191, 0, Nil(), out) to multiplier<br \/>\nSo, is this Turing complete? You bet: it&#8217;s got peano numbers, conditionals, and recursion. If you can do those three, you can do anything.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s pathological language is a bit of a treat for me. I&#8217;m going to show you a twisted, annoying, and thoroughly pointless language that *I* created. The language is based on a model of computation called [Actors](http:\/\/en.wikipedia.org\/wiki\/Actor_model), which was originally proposed by Professor Gul Agha of UIUC. There&#8217;ve been some really nice languages built using [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[92],"tags":[],"class_list":["post-208","post","type-post","status-publish","format-standard","hentry","category-pathological-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-3m","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/208","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=208"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/208\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=208"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=208"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}