editor | ||
node | ||
shared | ||
unison-src | ||
yaks | ||
.dockerignore | ||
.gitignore | ||
.travis.yml | ||
config | ||
development.markdown | ||
editor.yaml | ||
LICENSE | ||
README.md | ||
stack.yaml | ||
vagrant-provision.sh | ||
Vagrantfile |
The Unison platform
Unison is a new programming language, currently under active development. It's a modern, statically-typed purely functional language, similar to Haskell, but with a unique ability to describe entire distributed systems with a single program. Here's a simple example:
-- comments start with `--`
-- alice : Node, bob : Node
do Remote
x = factorial 6
Remote.transfer alice
y = foo x -- happens on `alice` node
Remote.transfer bob
pure (bar x y) -- happens on `bob` node
The do Remote
introduces a "remote block", where computation may proceed on multiple Unison nodes:
- The
Remote.transfer alice
transfers control of the computation to thealice
node. - The
foo x
call happens on thealice
node. - At each transfer, any required definitions (such as
foo
andx
) will be dynamically deployed to thealice
node and cached for future use. - The
Remote.transfer bob
transfers control of the rest of the computation to thebob
node. - The
bar x y
computation happens on thebob
node. Again, any needed definitions (bar
,x
, andy
) will be dynamically deployed to thebob
node.
This dynamic transfer / deployment of arbitrary computations is possible because definitions in Unison are identified by a cryptographic hash of their content, including the hashes of all dependencies (the hash is also "nameless" as it isn't affected by naming of variables). To transfer a computation, we send it to the recipient, and the recipient checks to see if the computation references any unknown hashes. Any unknown hashes are synced to the recipient before the transfer completes and the computation proceeds.
If you'd like to learn more about the project, the talk How to write a search engine in 15 lines of code has more of an introduction to the language.
Since Unison isn't terribly useful in its current form, the rest of this README will focus on stuff that will be of interest for potential contributors, namely, how to build the code, and a brief tour of the (fairly small but action-packed) codebase. If you're just interested in the project and want to follow along with the progress, unisonweb.org is the place to go, or you can also say hello or lurk in the chat room.
Still here? All right then! Let's get to it.
A brief code tour
First, a bit of orientation. Here's the directory structure:
yaks/
has subprojects for various utilties not specific to Unison (the result of "yak-shaving"). Once mature, each of these might be moved to independent projects and published on Hackage.shared/
has the Unison syntax tree, parser, typechecker. Depends onyaks/
node/
has code related to the Unison runtime and codebase editor. Depends onshared/
editor/
has some prototype work on a semantic editor for Unison. Also depends onshared/
. It's currently being allowed to bitrot, but may be resurrected at some point soon, or else rewritten.
Building using Stack
If these instructions don't work for you or are incomplete, please file an issue.
The build uses Stack. If you don't already have it installed, version 1.3 or later, follow the install instructions for your platform. Once that's done and the stack
executable is on your path, do:
$ git clone https://github.com/unisonweb/unison.git
$ cd unison
$ stack --version # make sure this returns 1.3 or later
$ stack setup
$ stack build unison-node
You'll need xz
on your path and also the libghc-curl-dev
library someplace that stack looks for it. See the [Vagrant box setup][#vagrant] and the vagrant-provision.sh script for known-good setup steps on linux.
See development.markdown
for a list of build commands you'll likely use during development.
A brief tour of the Haskell code
In the shared/
project:
Unison.Term
andUnison.Type
have the syntax trees for terms and types. In bothTerm
andType
, the same pattern is used. Each defines a 'base functor' type,F a
, which is nonrecursive, and the actual thing we use is an abstract binding tree over this base functor, anABT F
.ABT
(for 'abstract binding tree') is defined inUnison.ABT
. If you aren't familiar with abstract binding trees, here is a nice blog post explaining one formulation of the idea, which inspired theUnison.ABT
module. A lot of operations on terms and types just delegate to genericABT
operations.Unison.Parsers
has the main entry point for the parser.Unison.Typechecker.Context
is the implementation of the typechecker, andUnison.Typechecker
has the "public interface to the typechecker" and some convenience functions. There isn't a lot of code here (about 700 LOC presently), since the typechecking algorithm is pretty simple. Unlike a unification-based typechecker, where the typechecking state is an unordered bag of unification constraints and higher-rank polymorphism is usually bolted on awkwardly later, Dunfield and Krishnaswami's algorithm keeps the typechecking state as a nicely tidy ordered context, represented as a regular list manipulated in a stack-like fashion, and the algorithm handles higher-rank polymorphism very cleanly. They've also extended this work to include features like GADTs, though this new algorithm hasn't been incorporated into Unison yet.Unison.Codebase
has and interface and implementation for manipulating a Unison codebase
In the node/
project, there are currently 2 executables, container
and unison
, which you can build via stack build unison-node
:
unison
is a command line tool for editing a Unison codebase. It provides a handful of commands for adding new definitions, and editing or viewing existing definitions.container
has an HTTP interface to the Unison runtime, seedevelopment.markdown
for instructions on how to use. Eventually, thecontainer
functionality will get folded into theunison
executable.
That's all for now!
Appendix
VM build instructions
If you'd prefer to develop on a VM, you can still use your local text editor or IDE of choice for Haskell editing, since the filesystem is shared between the VM and your local machine.
Here are instructions for this route:
- Download and install Vagrant.
- Download and install VirtualBox. This is a free VM provider.
Once those are done, from the root directory of the project (the same directory as the Vagrantfile
file), do:
$ vagrant up
... lots of log output as the machine gets set up
Once it completes, you can do vagrant ssh
, then cd /vagrant
. Notice that the /vagrant
directory on the VM mirrors the root directory of your project. You can edit the code on your local machine, and use the the usual build instructions on the VM to compile and run the project on the VM!