{"id":19115417,"url":"https://github.com/polytypic/joincml","last_synced_at":"2025-04-30T23:10:14.320Z","repository":{"id":32826263,"uuid":"36419236","full_name":"polytypic/JoinCML","owner":"polytypic","description":null,"archived":false,"fork":false,"pushed_at":"2015-06-11T04:30:11.000Z","size":224,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-19T09:33:46.040Z","etag":null,"topics":["hobby-project"],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/polytypic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-28T06:31:05.000Z","updated_at":"2023-01-26T11:10:58.000Z","dependencies_parsed_at":"2022-09-05T15:21:40.227Z","dependency_job_id":null,"html_url":"https://github.com/polytypic/JoinCML","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polytypic%2FJoinCML","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polytypic%2FJoinCML/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polytypic%2FJoinCML/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polytypic%2FJoinCML/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/polytypic","download_url":"https://codeload.github.com/polytypic/JoinCML/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251795415,"owners_count":21645023,"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":["hobby-project"],"created_at":"2024-11-09T04:46:20.263Z","updated_at":"2025-04-30T23:10:14.281Z","avatar_url":"https://github.com/polytypic.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JoinCML\n\nA research project to create an extension of CML with a `join` combinator.\n\nThe core of CML-style events, or alternatives, boils down to two types:\n\n```fsharp\ntype Alt\u003c'x\u003e\ntype Ch\u003c'x\u003e\n```\n\nAnd a set of combinators:\n\n```fsharp\nmodule Ch =\n  val create: unit -\u003e Ch\u003c'x\u003e\n  val give: Ch\u003c'x\u003e -\u003e 'x -\u003e Alt\u003cunit\u003e\n  val take: Ch\u003c'x\u003e -\u003e Alt\u003c'x\u003e\n\nmodule Alt =\n  val choice: Alt\u003c'x\u003e -\u003e Alt\u003c'x\u003e -\u003e Alt\u003c'x\u003e\n  val withNack: (Alt\u003cunit\u003e -\u003e Alt\u003c'x\u003e) -\u003e Alt\u003c'x\u003e\n  val afterAsync: ('x -\u003e Async\u003c'y\u003e) -\u003e Alt\u003c'x\u003e -\u003e Alt\u003c'y\u003e\n  val sync: Alt\u003c'x\u003e -\u003e Async\u003c'x\u003e\n```\n\nThe idea of\n[Transactional Events](http://www.cs.rit.edu/~mtf/research/tx-events/ICFP06/icfp06.pdf)\n(TE) is to extend CML-style events to a monad (with plus).  The result is a\nhighly expressive synchronization mechanism with some surprising and interesting\n[Programming Idioms](http://arxiv.org/pdf/1002.0936.pdf).\n\nThe idea of JoinCML is to extend CML-style alternatives just far enough to form\nan applicative functor.  More specifically by adding a single new combinator:\n\n```fsharp\nmodule Alt =\n  val join: Alt\u003c'x\u003e -\u003e Alt\u003c'y\u003e -\u003e Alt\u003c'x * 'y\u003e\n```\n\nInformally, the semantics is that the two given alternatives must both be\navailable simultaneously in order for the alternative to complete.\n\nUsing `join` one can implement the `\u003c*\u003e` operation of applicative functors as:\n\n```fsharp\nlet (\u003c*\u003e) x2yA xA =\n  Alt.join x2yA xA\n  |\u003e Alt.after (fun (x2y, x) -\u003e\n     x2y x)\n```\n\nUnlike TE, JoinCML essentially retains all of CML as a subset, including\nnegative acknowledgments and the semantics of having only a single commit point.\nSee [JoinCML.fsi](JoinCML/JoinCML.fsi) for the signature of primitive\ncombinators and [Convenience.fsi](JoinCML/Convenience.fsi) for non-primitive\nconvenience combinators.\n\nUnsurprisingly, it appears that basically the same idea has already been\ndiscovered earlier in the form of\n[Conjoined Events](https://kar.kent.ac.uk/33878/1/Conjoined.pdf).  Thanks to\nMatthew Fluet for finding the paper!\n\nThis project seeks to answer the following questions:\n\n* What can JoinCML express that CML cannot express?\n* What cannot JoinCML express that TE can express?\n* Does JoinCML have favorable properties when compared to TE?\n* Can JoinCML be implemented efficiently?\n* What sort of programming idioms work with JoinCML?\n\nHere are some working hypotheses:\n\n* CML ⊊ JoinCML ⊊ TE.  That is, JoinCML is strictly more expressive than CML and\n  TE is strictly more expressive than JoinCML.\n* JoinCML allows n-way rendezvous to be implemented for any n determined before\n  the synchronization.  TE allows the n to be determined during synchronization.\n  CML only allows 2-way rendezvous.\n* JoinCML subsumes core\n  [join-calculus](http://research.microsoft.com/en-us/um/people/fournet/papers/join-tutorial.pdf).\n* JoinCML is significantly less expensive to implement than TE, because\n  synchronization does not require evaluating events step-by-step during\n  synchronization.\n* JoinCML is better suited to impure languages than TE, because synchronization\n  does not require running arbitrary code and thus there is no danger of\n  performing side-effects that cannot be rolled back.\n\nOne way to gain some additional intuition is that JoinCML alternatives can be\nrewritten to a [DNF](http://en.wikipedia.org/wiki/Disjunctive_normal_form)-style\nnormal form that roughly looks like\n\n```fsharp\n(p11 \u003c\u0026\u003e ...) \u003c|\u003e (p21 \u003c\u0026\u003e ...) \u003c|\u003e ...\n```\n\nwhen we use `\u003c|\u003e` for `choice` and `\u003c\u0026\u003e` for `join` and the `pij` are operations\non channels.  Ordinary CML doesn't have `\u003c\u0026\u003e` aka `join`, so in ordinary CML the\nnormal form is just\n\n```fsharp\np1 \u003c|\u003e p2 \u003c|\u003e ...\n```\n\nIn both of the above, the resulting normal forms are finite.  TE does not have\nsuch a normal form.  It is even possible to express a pair of processes using TE\nthat exchange messages indefinitely without completing a transaction.\n\nAt this point JoinCML is vaporware, but I definitely plan to try find an\nefficient implementation.  (Of course, most of JoinCML can be trivially\nimplemented in TE.)\n\nSome examples have been drafted:\n\n* 3-way swap channel in [Swap3.fsi](Examples/Swap3.fsi) and\n  [Swap3.fs](Examples/Swap3.fs).\n* Dining Philosophers [Dining.fs](Examples/Dining.fs) using `MVar`s defined in\n  [MVar.fsi](Examples/MVar.fsi) and [MVar.fs](Examples/MVar.fs).\n* Synchronous channel with guarded receive in\n  [GuardedCh.fsi](Examples/GuardedCh.fsi) and\n  [GuardedCh.fs](Examples/GuardedCh.fs).\n* Translations of examples based on join-calculus in\n  [Join.fs](Examples/Join.fs).\n\nContributions and collaborators are welcome!  In particular, if you have\ninteresting concurrent programming problems to solve, it would be interesting to\ntry to express solutions to them using JoinCML.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolytypic%2Fjoincml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolytypic%2Fjoincml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolytypic%2Fjoincml/lists"}