{"id":270,"date":"2007-01-12T10:54:05","date_gmt":"2007-01-12T10:54:05","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2007\/01\/12\/programs-as-poetry-fishy-programming-in-homespring\/"},"modified":"2007-01-12T10:54:05","modified_gmt":"2007-01-12T10:54:05","slug":"programs-as-poetry-fishy-programming-in-homespring","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2007\/01\/12\/programs-as-poetry-fishy-programming-in-homespring\/","title":{"rendered":"Programs as Poetry: Fishy Programming in Homespring"},"content":{"rendered":"<p> I&#8217;m hitting on something deeply twisted this week. It&#8217;s called <a href=\"http:\/\/spuzz.net\/projects\/homespring\/about.php\"><em>homespring<\/em><\/a>. Homespring is interesting for two reasons. First, it&#8217;s got a sort of reverse flavor to it: it consists of active agents in a passive structure. So, for example, you can&#8217;t do anything like control flow &#8211; that&#8217;s a dynamic change in the control flow of the program; in Homespring, you need to trick the agents into doing something using the static, unchanging structure of the program. And second, it challenges you to write your program in the form of a poem! And the icing on the cake? The agents are salmon,<br \/>\nand the passive structure is a network of streams.<\/p>\n<p><!--more--><\/p>\n<p> The syntax of Homespring is set up to look as much like english as possible. But don&#8217;t let that<br \/>\nfool you &#8211; the english syntax is just an artifact, a facade. It doesn&#8217;t parse anything like english.<br \/>\nThe tokens consist of groups of characters things separated by <em>single<\/em> spaces or carriage returns, with &#8220;.&#8221; as an escape character. So for example, &#8220;Hello world&#8221; is two tokens; &#8220;Hello. World&#8221; is one token &#8211; the &#8220;.&#8221; is an escape character that turns the space between &#8220;Hello&#8221; and &#8220;World&#8221; into a part of a single token consisting of the string &#8220;Hello World&#8221;. To make matters a bit more confusing, since unescaped spaces <em>always<\/em> separate tokens,  if you&#8217;ve got <em>two<\/em> spaces next to each o, then they separate an <em>empty<\/em> token between them. &#8220;Hello  World&#8221; is actually three tokens, &#8220;Hello&#8221;, &#8220;&#8221;, and &#8220;World&#8221;.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"homespring-parsing-examples.jpg\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_129.jpg?resize=221%2C301\" width=\"221\" height=\"301\" class=\"inset right\" \/><\/p>\n<p> The way that the program is parsed is quite straightforward. The program is parsed into a simple<br \/>\ntree of tokens; each token is a child of the token immediately before it, with one exception. If there<br \/>\nis an empty token, then the parser jumps back up one level in the tree, and adds the next token to the previous node up the tree.  This diagram shows you a few examples.<\/p>\n<p> The root of the tree is the ocean; each node in the tree is either a spring which is a source of water and also where salmon can spawn (if their name is not a keyword), or a primitive object (if they have a keyword name); paths in the tree between springs and the ocean are streams. Salmon<br \/>\nare created by reading lines of input: each line of input is wrapped in a salmon, which tries to swim upstream until it reaches its home spring &#8211; that is, a spring whose name matches the string it wraps. If it reaches either its home or a leaf of the tree, it will <em>spawn<\/em>. When a salmon spawns,<br \/>\nit becomes <em>mature<\/em>, creates a new salmon which contains the name of the spring, and both the salmon and its spawn start to swim downstream to the ocean. When a salmon swims downstream and reaches the ocean, it&#8217;s string is output.<\/p>\n<p> I&#8217;ll explain the primitives as we go along. Let&#8217;s start with an example. The easiest example to write is <em>almost<\/em> the good old &#8220;Hello world&#8221;, except that this version is basically an endless loop.<\/p>\n<pre>\nbear hatchery Hello,. World..  powers\n<\/pre>\n<p> First, let&#8217;s see how that parses. &#8220;bear&#8221;  is followed by a single space, so it&#8217;s a token, and it&#8217;s at the ocean. &#8220;hatchery&#8221; is also followed by a single space so it&#8217;s a token, and it&#8217;s places as a child of &#8220;bear&#8221;. Then we&#8217;ve got &#8220;Hello,. World&#8221;. The space is quoted by a &#8220;.&#8221;, so that&#8217;s one token, and it&#8217;s places as a child of &#8220;hatchery&#8221;. There there are two spaces &#8211; so there&#8217;s an empty token, so the insertion point for new tokens moves up one level &#8211; inserts will happen as children of &#8220;hatchery&#8221;. And finally, there&#8217;s &#8220;powers&#8221;, which will be placed as a child of &#8220;hatchery&#8221;. So the parse tree is:<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"hello-loop.jpg\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_130.jpg?resize=170%2C104\" width=\"170\" height=\"104\" \/><\/p>\n<p> To understand what this does, we need to understand the three primitives in here: &#8220;bear&#8221;, &#8220;hatchery&#8221;, and &#8220;powers&#8221;.<\/p>\n<ol>\n<li> The &#8220;bear&#8221; primitive eats mature salmon, but won&#8217;t eat salmon that haven&#8217;t spawned. So<br \/>\nit will prevent any mature salmon from getting to the ocean.<\/li>\n<li> The &#8220;hatchery&#8221; primitive spawns young salmon containing the string &#8220;homeless&#8221; which swim upstream. It only spawns while it is receiving electricity from downstream.<\/li>\n<li> The &#8220;powers&#8221; primitive is a hydro plant which generates electricity, and sends it upstream.<\/li>\n<\/ol>\n<p> So what happens in this program is that the &#8220;powers&#8221; generates electricity which feeds the &#8220;hatchery&#8221;. The hatchery spawns homeless young salmon, which swim upstream to &#8220;Hello, World&#8221;, and then,<br \/>\nsince they&#8217;re at a leaf, they spawn, turning mature, and swim downstream. The young salmon that they spawn contain the string &#8220;Hello world.&#8221;, and they also swim downstream. The hatchery doesn&#8217;t affect the salmon swimming past it, so they get to the bear. The bear eats the mature salmon, leaving only the young, which get to the ocean &#8211; and so &#8220;Hello, World.&#8221; gets output for each salmon that reaches the ocean. Since the hatchery is being powered continuously, it keeps spawning salmon, so there will be a continuous flow of salmon getting to the ocean and printing.<\/p>\n<p> So, what about doing it just once? Here&#8217;s where it gets really silly. Here&#8217;s a halting program<br \/>\nthat prints &#8220;Hello World!&#8221; once:<\/p>\n<pre>\nUniverse of bear hatchery says Hello. World!.\nIt   powers      the marshy things\nthe power of the snowmelt overrides.\n<\/pre>\n<p> Before we look at the parsetree for that, let&#8217;s go through the new primitives.<\/p>\n<ol>\n<li> &#8220;snowmelt&#8221;: a source of water that flows downstream, one node each step. Many things<br \/>\nare destroyed by snowmelt.<\/li>\n<li> &#8220;marshy&#8221;: a marshy node is a node that slows snowmelt. Snowmelt takes two steps to<br \/>\npass through a marshy node.<\/li>\n<li> &#8220;universe&#8221;: the world of the program. If snowmelt hits the universe, the program halts.<\/li>\n<\/ol>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"Hello-world-parsetree.jpg\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_131.jpg?resize=234%2C290\" width=\"234\" height=\"290\" class=\"inset right\" \/><\/p>\n<p> So, let&#8217;s see the parsetree, and work through how the program works. When the program<br \/>\nstarts (time=0),\ttwo things happen. Power from the power plant starts to flow, and snowmelt starts to run upstream. At time=1, the snowmelt is at &#8220;the&#8221;; and the power reachers &#8220;It&#8221;. At time=2, the snowmelt reaches &#8220;of&#8221;, and the power reaches the hatchery, which turns on. At time=3, the hatchery produces a salmon which swims up to &#8220;says&#8221;, and the snowmelt reaches &#8220;power&#8221; (not &#8220;powers&#8221;, which would be another power plant. This is just a spring.) At time=4, the salmon reaches &#8220;Hello world&#8221;, turns mature, and spawns, and the snowmelt reaches &#8220;the&#8221;. At time=5, both the newly spawned young &#8220;Hello world&#8221; salmon and the mature homeless salmon reach &#8220;says&#8221;; and the snowmelt reaches &#8220;things&#8221;. At time=6, the two salmon get back to the hatchery, and the snowmelt reaches the marsh. At time=7, the two salmon reach &#8220;bear&#8221;, and the mature salmon gets eaten. The snowmelt is doesn&#8217;t move; it&#8217;s slowed by the marsh. At time=8, the young salmon reaches &#8220;of&#8221;, and the snowmelt gets out of the marsh and reaches &#8220;the&#8221;. Finally, at time=9, the young salmon reaches &#8220;Universe&#8221; which is the root of the tree, and thus the ocean, so it gets to print. Then the snowmelt arrives, hits Universe, and the program halts. Simple, right?.<\/p>\n<p> There are a ton of other primitives that I&#8217;m not going to go through; I strongly recommend that you visit the Homespring site, and read the <a href=\"http:\/\/spuzz.net\/files\/hs.pdf\">language reference<\/a> yourself. It&#8217;s a great piece of work. And this is a really fun language to play with; one of the goals of the language is for your<br \/>\nprograms to read as poems &#8211; the challenge is to figure out how to write it as a poem with a natural flow, and yet still have all of the timings work out right! The manual also includes several other wonderful sample programs.<\/p>\n<p> Just to give you a flavor, here&#8217;s a longer program &#8211; it&#8217;s a program that inputs two single-digit numbers, and prints out their sum.<\/p>\n<pre>\nUniverse is marshy but evaporates downstream. Sense the rapids reverse. Down\nbridge is now marsh:\nMarshy marshy marshy marshy marshy marshy marshy marshy marshy marshy now.\nAll evaporates downstream. Sense\nthe rapids now:\nRapids rapids rapids rapids rapids rapids rapids rapids sensed.\nUgh +.\nTake powers from                  snowmelt  therefore;\nthe   current time is of youth. Fountain is young. Bear cannot\nreverse. Down inverse. Lock young. Switch young. Range. Switch clone to the\nswitch itself. Now inverse. Lock narrows down:\nPowers\nto   append. Up go all young. Bear time evaporates\nthen. Therefore:\nSpawn power. Invert evaporates it. Down force. Down reverse. Down net. The\nnet reverses force.\nNow try:\nAdd add add add add add add now.\nIt is not possible; now count:\n0.\n1.\n2.\n3.\n4.\n5.\n6.\n7.\n8.\n9.\n10.\n11.\n12.\n13.\n14.\n15.\n16.\n17.\n18+.\nYou   can   now   pump\nin reverse. Down lock goes; narrows lock down:\nInverse. Lock young. Range. Sense 0n 1n 2n 3n 4n 5n 6n 7n 8n 9n\nPowers         lock time now.\nInverse. Lock young. Range. Sense 0n 1n 2n 3n 4n 5n 6n 7n 8n 9n\nPowers            snowmelt   now.\nPowers\nall:\nBear hatchery n\npowers\ninsulated bear hatchery ?.\nHydro. Power spring as\nsnowmelt         powers   snowmelt  then, and disengage.\nHYDRO!!\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m hitting on something deeply twisted this week. It&#8217;s called homespring. Homespring is interesting for two reasons. First, it&#8217;s got a sort of reverse flavor to it: it consists of active agents in a passive structure. So, for example, you can&#8217;t do anything like control flow &#8211; that&#8217;s a dynamic change in the control flow [&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-270","post","type-post","status-publish","format-standard","hentry","category-pathological-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-4m","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/270","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=270"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/270\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=270"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=270"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}