{"id":17862689,"url":"https://github.com/stevana/smarrow-lang","last_synced_at":"2025-10-11T22:23:38.982Z","repository":{"id":172713196,"uuid":"649601673","full_name":"stevana/smarrow-lang","owner":"stevana","description":"Experimental programming language where programs are state machines expressed in arrow notation","archived":false,"fork":false,"pushed_at":"2023-06-28T11:39:20.000Z","size":135,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-08T11:34:52.811Z","etag":null,"topics":["distributed-systems","programming-language","state-machines"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stevana.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-05T08:32:22.000Z","updated_at":"2024-08-31T04:52:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"7d742d79-2c3f-4300-82bb-470fe1b84532","html_url":"https://github.com/stevana/smarrow-lang","commit_stats":null,"previous_names":["stevana/smarrow-lang"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevana%2Fsmarrow-lang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevana%2Fsmarrow-lang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevana%2Fsmarrow-lang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevana%2Fsmarrow-lang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stevana","download_url":"https://codeload.github.com/stevana/smarrow-lang/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246892848,"owners_count":20850850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["distributed-systems","programming-language","state-machines"],"created_at":"2024-10-28T08:54:41.053Z","updated_at":"2025-10-11T22:23:33.929Z","avatar_url":"https://github.com/stevana.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# smarrow-lang\n\n`smarrow-lang` is an experimental programming language where programs are state\nmachines expressed in [arrow\nnotation](https://www.haskell.org/arrows/syntax.html).\n\nState machines communicate with each other by sending messages, a bit like\nErlang processes but with more restrictions. For example, a state machine may\nnot spawn new state machines, and its state, input and output types are\nspecified at compile time.\n\nThese restrictions, or extra structure, are the basis for (to be implemented)\nfeatures such as:\n\n* Hot-code swapping;\n* Type-safe state migrations;\n* Input and output evolution.\n* [Simulation testing](https://apple.github.io/foundationdb/testing.html) and\n  formal verification.\n\nThe goal of the language is to provide a testbed for experimenting with how to\nprogram distributed systems.\n\n## Why a new language?\n\nBarbara Liskov gave two good reasons in her Turing award\n[lecture](https://amturing.acm.org/vp/liskov_1108679.cfm) (2008):\n\n\u003e \"Programmers write programs in programming languages, so programming language\n\u003e constructs are a very good way of communicating to programmers if you are\n\u003e trying to get them to understand how to build programs.\"\n\n\u003e \"There's a funny disconnect in how we write distributed programs. You write\n\u003e your individual modules, but then when you want to connect them together\n\u003e you're out of the programming language and into this other world. Maybe we\n\u003e need languages that are a little bit more complete now, so that we can write\n\u003e the whole thing in the language.\"\n\n## Getting started\n\n```bash\n$ cabal run smarrow-deploy \u0026\n$ cat example/Counter.smarr\n```\n```\nmachine Counter where\n\nstate : { count : Int = 0 }\n\nlanguage\n  : Incr -\u003e {}\n  | Read -\u003e Int\n\nfunction i -\u003e case i of\n  { Incr -\u003e do { s \u003c- get -\u003c {}; put -\u003c { count = s.count + 1 } }\n  ; Read -\u003e get -\u003c {}\n  }\n```\n```bash\n$ cabal run smarrow -- deploy counter example/Counter.smarr\nDeployed: counter\n$ cabal run smarrow -- invoke counter Incr\n{}\n$ cabal run smarrow -- invoke counter Read\n1\n```\n```diff\n$ diff -u example/Counter.smarr example/Counter2.smarr\n-   put -\u003c { count = s.count + 1 }\n+   put -\u003c { count = s.count + 2 }\n$ cabal run smarrow -- deploy counter example/Counter2.smarr\nUpgraded: counter\n```\n```bash\n$ cabal run smarrow -- invoke counter Read\n1\n$ cabal run smarrow -- invoke counter Incr\n{}\n$ cabal run smarrow -- invoke counter Read\n3\n$ fg\ncabal run smarrow-deploy\n^C\n```\n\n## Features\n\n### First-class state machines\n\nIn functional programming languages functions are first-class. In `smarrow` we\nexperiment with making state machines first-class instead.\n\n### Arrow notation\n\nState machines are to `smarrow` what functions are to functional programing\nlanguages. A state machine has the type:\n\n```haskell\n  input -\u003e state -\u003e (state, output)\n```\n\nIt's a bit clunky to have to thread through the state explicitly though. We\ncould have used a state monad and thereby get do-notation, which would improve\nthe egonomics of writing state machines, but in `smarrow` we go down an other\npath and use arrow notation instead for reasons we shall explain next.\n\n### Hot-code swapping\n\nConal Elliott's work on [compiling to\ncategories](http://conal.net/papers/compiling-to-categories/) shows how `Arrow`s\nthat don't use `arr` can be compiled to first-order combinators (Cartesian\nclosed categories).\n\nWe use this fact to compile our state machines (which are `Arrow`s that don't\nuse `arr`) to a bytecode inspired by Cartesian closed categories. This bytecode\ncan be sent over the write to remote nodes and update state machines without\ndowntime, similar to hot-code swapping à la Erlang.\n\n### Adapters\n\nState machines are pure, if we want them to do something useful we must hook\nthem up to inputs from the \"real world\". Adapters allow us to turn, for example,\nan HTTP server request into an input which we can then feed to a state machine\nand reply to the request using the output that the state machine produced.\n\nSimilary console I/O or a REPL could be used as adapters.\n\n### Simulation testing\n\nAnother useful adaptor is to deploy a bunch of communicating state machines on a\nfake network where all messages are kept in an in-memory priorty queue sorted by\narrival time. We can then simulate the network, by popping the queue, advancing\nthe clock to the arrival time, feed it to the receiving state machine, collect\nthe outputs, generate arrival times for the outputs and feed them back into the\nqueue. The arrival times are generated using a pseudo number generater fed with\na seed, this allows us to determinstically get different interleaving of\nmessages. The fact that we advance the clock to the arrival time makes timeouts\nhappen without having to wait for them, which is useful when combined with fault\ninjection of network faults. Essentially this gives us a discrete-event\nsimulation, which is much faster than testing using Jepsen and is determinstic\ntoo!\n\n### Time-travelling debugger\n\nIf we record all inputs that we feed the state machines, then we can implement a\ntime-travelling debugger by merely feeding the inputs one-by-one to the state\nmachines and observing how the states change over time.\n\nWe can use snapshots and fixed sized ring-buffers of inputs in case there are\ntoo many inputs to store then all.\n\n### Deployments via supervision trees\n\nXXX:\n\n### No modules or packages\n\nA state machine is a unit of deployment, unlike a (pure) function. A state\nmachine must be under version control before it can be deployed, it's therefore\nglobally uniquely identifiable and therefore there's no need to further package\nit up.\n\nState machines carry automatically checked semantic versioning and other\nmetadata making it possible to search for state machines, subscribe to\n(security) updates for ones that you've deployed, etc.\n\nSee also:\n\n* https://erlang.org/pipermail/erlang-questions/2011-May/058768.html\n* https://lobste.rs/s/xi3mi0/does_programming_language_with_ml_style\n* Unison\n\n### Upgrades\n\nAfter a system is deployed it will likely need to be upgraded.\n\nXXX: we already talked about hot-code swapping...\n\n* Patches vs upgrades, semantically check inputs and outputs for changes?\n\n* VM upgrades? How does Erlang deal with them?\n\n### Protocols\n\nA state machines input type essentially defines its API, it doesn't say anything\nabout which sequences of inputs are allowed. Consider the POSIX filesystem API\nwhere we can open a file to get a file handle, which we can then read and write\nto, at the end we are supposed to close the file handle and once closed no\nfurther reads or writes are allowed. These legal sequences of inputs define the\nprotocol. One way to encode protocols is by means of a state machines.\n\nProtocols can be enforced at run-time by protocol checkers that sit in-between\nstate machines.\n\n### Horizonal composition -- pipelining\n\nXXX: Horizontally compose state machines.\n\n* [Jim Gray on parallelism via pipelining](https://youtu.be/U3eo49nVxcA?t=1949)\n\n### Vertical composition\n\n### Capabilities\n\n* Lecture on [capabilities](https://youtube.com/watch?v=TQhmua7Z2cY) from MIT's\n  6.858 Computer Systems Security course (2014)\n* [The Heart of Spritely: Distributed Objects and Capability\n  Security](https://spritely.institute/static/papers/spritely-core.html)\n\n### Formal verification\n\n* Model-checking à la TLA+: https://github.com/Gabriella439/HasCal\n* https://lawrencecpaulson.github.io/2022/10/12/verifying-distributed-systems-isabelle.html\n\n## Contributing\n\nIf any of this sounds interesting, feel free to get in touch.\n\n### To do\n\n* records\n* state migration\n* parametrised inputs/sums of products\n* api evolution\n* deprecation of machines?\n* persistence\n* typechecker\n* state invariants?\n* pre-conditions on input?\n* pretty printer\n  - and formatter?\n* cli\n  - rustup?\n* encryption\n* tunnel, https://tunnelto.dev or https://github.com/pcarrier/srv.us ?\n* migrate deployment\n  - automatic failover?\n* observability\n* debugger\n* optimise encoding of messages based on frequency in previous deployment?\n* echo server benchmark\n\n## See also\n\n* The P programming language\n* https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/arrows.html\n* https://www.haskell.org/arrows/sugar.html\n* https://hackage.haskell.org/package/arrowp-qq-0.3.0/src/\n* https://karczmarczuk.users.greyc.fr/TEACH/Stage/ArrComp.pdf\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevana%2Fsmarrow-lang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstevana%2Fsmarrow-lang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevana%2Fsmarrow-lang/lists"}