Last week we released another Unison alpha milestone. This release has anumber of bugfixes and performance improvements.🌈⭐️
It's exciting to see Unison gradually coming together, but even more exciting has been seeing people writing and publishing Unison code. I've been pretty busy reviewing pull requests to theUnison base libraries,and there's already a lot of useful stuff there. Thanks to everyone who has contributed so far!
A number of folks have been working on their own Unison libraries and we're collecting theseon a page of this site.I want to highlight just one of these, which is a random number generator. There are many other cool libraries, but I picked this one at random. The main thing I want to highlight is just how easy it is to create and use Unison libraries.
Starting up
If you've been putting off trying out Unison because you think getting into a new language might be a lot of work and involve a lot of setup, then I've got good news for you: Unison requires almost no setup. You can just start coding.
To get going with Unison, you can go through thethree minute quickstart guide.It only has three steps.
Once set up,ucm
starts the Unison Codebase Manager:

I can now just start writing Unison code in any file in the directory from which I starteducm
,as long as that file's name ends in.u
.I open up a filescratch.u
withvim
(my favorite editor), and write my first definition, the obligatoryfactorial
function:
factorial n = List.foldr (*) 1 (range 2 (n + 1))
If I save my scratch file, Unison responds with:

It's telling me thatfactorial
is a function that takes aNat
(a 64-bit unsigned integer), and returns anotherNat
.I can add this function to my codebase:

I can try out my function right in the scratch file by adding a "watch expression", which is any line that starts with>
(or an indentation block where the first line starts with>
).
> factorial 10
Unison reponds by evaluating my expression:

Looking around the base library
Thebase
library is already full of good stuff, with new things being added almost daily now. To see what's here, I can browse with UCM. If I dolist .base
(orls .base
),I get a long list. I cancd
into any namespace and look around withls
.
In the definition offactorial
above, I was usingfoldr
andrange
.If I ask UCM tofind range
,it responds with everything it knows about withrange
in the name:

The second entry is the function I was using,List.range
.I can ask for its definition either by name or by using the number from the list that UCM produced:

Thedocs
command (tryhelp docs
)shows me the documentation for a given function or type, if it has any docs associated with it.

Let's have a look at a third-party library
Looking at thelist of libraries that people have already made,I want to pick one, kind of at random, and just play with it to give you a feel for what it's like to consume libraries in Unison. And speaking of random, it looks like one of them isa random number generator that uses a Mersenne twister,written by Chris Gibbs. Let's try that out.
Chris has supplied handy install instructions, so let's just do as he says:
.> pull https://github.com/atacratic/unison-random-mersenne.git:.releases._v1 external.unison_random_mersenne.v1
Lots of stuff scrolls by, and Chris's library is now in my codebase. The namespaceexternal.unison_random_mersenne.v1
is kind of long for my taste, so I'm just going to move it underlib.rng
.
.> move.namespace external.unison_random_mersenne.v1 lib.rng
I'm using tab completion for this instead of typing out the whole thing. Icd lib.rng
and look around.

Looks like there's aREADME
,which is a Unison value of typeDoc
.I can ask UCM to render anyDoc
with thedisplay
command. In theREADME
there's a usage example which shows me how to generate some random numbers.
I put a triple dash---
,a "fold", on a line at the top of myscratch.u
file, which tells Unison to ignore everything below. I've already addedfactorial
to my codebase, so I don't need to think about that anymore. It goes below the fold. Above the fold, I put an expression to generate a single random number between 0 and 10 which I got from the README.
> mersenne.provide (nextFromRange 0 11) defaultSeed 'ask
---
factorial n = List.foldr (*) 1 (range 2 (n + 1))
I wonder what thismersenne.provide
is. Let's ask Unison.

OK, soprovide
generates numbers by providing aStore State
ability, whereState
is the Mersenne twister's internal state. TheNat32
is the seed, and thisAsk n
thing is a computation that can ask for a randomn
(which in my case is going to beNat
).
Looks like this library puts a lot of its guts on display, so I'm going to try to write a more abstract interface for it. What I really want for a random number generator ability is something like this:
ability RNG where
nextNat : Nat
I can write a (recursive) handler for this ability that uses the Mersenne twister:
mersenneRNG : Nat32 -> '{RNG,e} a ->{e} a
mersenneRNG seed x =
h = cases
{ nextNat -> k } -> handle (k !nat.next) with h
{ a } -> a
mersenne.provide '(handle !x with h) seed 'ask
Great! So now I can request a randomNat
just by sayingnextNat
,and I can handle that request with `mersenneRNG`by providing a seed. But sometimes I don't want to provide a seed, and I just want to generate a random number as anIO
effect. Let's try to feed it the system time.

OK, we can get anEpochTime
,which wraps aNat
,usingsystemTime
.Can we turn that into aNat32
as required bymersenneRNG
?A type-basedfind
turns up 3 different functions:

Skimming thedocs
for these, I see thattruncate32
is probably the thing I want. It truncates the high 32 bits, leaving me with just the least significant bits of the clock. So I write:
clockSeed : '{IO} Nat32
clockSeed _ =
match !systemTime with
EpochTime t -> truncate32 t
And finally I use themersenneRNG
handler from earlier:
mersenneIO : '{RNG,e} a ->{IO,e} a
mersenneIO x =
mersenneRNG !clockSeed x
An example of using this in a program might be:
main : '{IO} ()
main = 'let
printLine (Nat.toText (mersenneIO 'nextNat))
Iadd
all of that to ascratch
namespace in my codebase:

Let's try to run it. UCM provides arun
command which provide theIO
ability to something of a type like'{IO} a
.

Great! I got a random number using the system clock time as a seed. Maybe at some point I'llsend a pull requestto Chris so he can incorporate some of this into his library.
Conclusion
I hope this gives you a taste of what it's like to work in Unison with the current alpha release, and that this encourages you to try it out and maybe contribute some libraries. Remember, it's early days yet, so little things you build now could make a big impact on the Unison community for the future.