https://github.com/polytypic/poc.cml
https://github.com/polytypic/poc.cml
Last synced: about 1 month ago
JSON representation
- Host: GitHub
- URL: https://github.com/polytypic/poc.cml
- Owner: polytypic
- License: epl-1.0
- Created: 2015-05-01T12:54:44.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2015-05-05T08:33:46.000Z (over 10 years ago)
- Last Synced: 2025-04-30T23:01:46.389Z (9 months ago)
- Language: Clojure
- Homepage:
- Size: 238 KB
- Stars: 25
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](http://clojars.org/poc.cml)
# poc.cml
Proof-of-Concept CML-style composable first-class events on top of
[core.async](https://github.com/clojure/core.async/).
## Why and what is CML?
Concurrent ML is a concurrent programming language developed by
[John Reppy](http://people.cs.uchicago.edu/~jhr/) in the late 1980's and early
1990's. It is based on ideas, namely synchronous message passing and
non-deterministic choice, that you can find in
[CSP](http://en.wikipedia.org/wiki/Communicating_sequential_processes) and
[Pi-calculus](http://en.wikipedia.org/wiki/%CE%A0-calculus). CML then extends
the idea of non-deterministic choice over synchronous channel operations to
first-class composable events with negative acknowledgments (nacks).
With plain core.async, one can express a non-deterministic choice over a linear
sequence of synchronous get and put operations:
```clojure
(alt!
([] ) ;; get operation
[ ] ([] ) ;; put operation
...)
```
With CML, one has the following combinators (and more) for expressing
first-class events:
```clojure
(gete ) ;; An event to take a value on a channel
;; and alternative syntax for gete
(pute ) ;; An event to give a value on a channel
[ ] ;; and alternative syntax for pute
(choose ...) ;; Non-deterministic choice over events
(wrap ) ;; An event with a post synchronization action
(guard ) ;; An event with a pre synchronization action
(with-nack event-fn>) ;; An event with a pre sync action given a nack
```
Compared to plain core.async, non-deterministic choices can be easily nested and
actions can be attached both before and after synchronization. Furthermore,
there is a combinator that provides negative acknowledgment in case an event
wasn't ultimately chosen.
The plain core.async `alt!` grammar can be expressed using just a subset of the
combinators
```clojure
(sync!
(choose
(wrap (gete ) (fn [] ))
(wrap (pute ) (fn [] ))
...))
```
where `sync!` is an operation that synchronizes on a given event and returns its
result. For convenience, `sync!` has an implicit `choose`, so the `choose` can
be dropped, and we can also use the alternative syntax for `gete` and `pute`:
```clojure
(sync!
(wrap (fn [] ))
(wrap [ ] (fn [] ))
...)
```
Written this way, the `sync!` expression is just slightly more verbose than the
`alt!` expression, and we could certainly add further sugar to make the `sync!`
version more concise, but the key here is that the combinators `choose`, `wrap`,
`pute` and `gete` are just ordinary functions that return values that can be
further manipulated with other combinators, stored in data structures and even
passed through channels.
BTW, note that `gete` and `pute` don't end with a bang `!`. That is because all
the effects are actually performed by `sync!` and the values returned by the
event combinators are immutable representations of selective synchronous
operations.
See the [examples](examples) for further documentation.
The book
[Concurrent Programming in ML](http://www.cambridge.org/us/academic/subjects/computer-science/distributed-networked-and-mobile-computing/concurrent-programming-ml)
is the most comprehensive introduction to Concurrent ML style programming.
## Next steps
What is interesting is that CML style events do not require significantly more
complicated machinery than what core.async already provides. This
proof-of-concept library hopefully makes that clear. For production use, you'd
want to implement the CML mechanisms directly. Also note the one exception
raised in the implemention [here](src/poc/cml.cljc#L45). The `alts!` operation
of core.async does not make it possible to distinguish between multiple
different operations on a single channel, which breaks composability.
## License
Copyright © 2015 Vesa Karvonen
Distributed under the Eclipse Public License either version 1.0 or (at your
option) any later version.