Last week we released another Unison alpha milestone. This release has a number 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 the Unison 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 these on 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 the three 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 started `ucm`

, as long as that file's name ends in `.u`

. I open up a file `scratch.u`

with `vim`

(my favorite editor), and write my first definition, the obligatory `factorial`

function:

`factorial n = List.foldr (*) 1 (range 2 (n + 1))`

If I save my scratch file, Unison responds with:

It's telling me that `factorial`

is a function that takes a `Nat`

(a 64-bit unsigned integer), and returns another `Nat`

. 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

The `base`

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 do `list .base`

(or `ls .base`

), I get a long list. I can `cd`

into any namespace and look around with `ls`

.

In the definition of `factorial`

above, I was using `foldr`

and `range`

. If I ask UCM to `find range`

, it responds with everything it knows about with `range`

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:

The `docs`

command (try `help 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 the list 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 is a 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 namespace `external.unison_random_mersenne.v1`

is kind of long for my taste, so I'm just going to move it under `lib.rng`

.

`.> move.namespace external.unison_random_mersenne.v1 lib.rng`

I'm using tab completion for this instead of typing out the whole thing. I `cd lib.rng`

and look around.

Looks like there's a `README`

, which is a Unison value of type `Doc`

. I can ask UCM to render any `Doc`

with the `display`

command. In the `README`

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 my `scratch.u`

file, which tells Unison to ignore everything below. I've already added `factorial`

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 this `mersenne.provide`

is. Let's ask Unison.

OK, so `provide`

generates numbers by providing a `Store State`

ability, where `State`

is the Mersenne twister's internal state. The `Nat32`

is the seed, and this `Ask n`

thing is a computation that can ask for a random `n`

(which in my case is going to be `Nat`

).

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 random `Nat`

just by saying `nextNat`

, 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 an `IO`

effect. Let's try to feed it the system time.

OK, we can get an `EpochTime`

, which wraps a `Nat`

, using `systemTime`

. Can we turn that into a `Nat32`

as required by `mersenneRNG`

? A type-based `find`

turns up 3 different functions:

Skimming the `docs`

for these, I see that `truncate32`

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 the `mersenneRNG`

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))
```

I `add`

all of that to a `scratch`

namespace in my codebase:

Let's try to run it. UCM provides a `run`

command which provide the `IO`

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'll send a pull request to 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.

## Updates

Get new blog posts delivered to your inbox.