The process of applying a potentially breaking change to your code need not be stressful. Here's how Unison handles that process in two common cases:
Updating your own code
Sometimes you'll need to make a change in the codebase that can't automatically be propagated to dependent functions, for example: if you alter a data constructor for a type or change the arguments to a function. Unison can programmatically guide you through the edits that you need to make in these cases.
Walk through an example
Let's say we have a simple type and a few functions which make use of that type in our codebase:
unique type Box = Box Nat
Box.toText : Box -> Text
Box.toText box = match box with
Box.Box nat -> Nat.toText nat
Box.print : Box -> {IO,Exception} ()
Box.print box =
Box.toText box |> printLine
myProject/main> add
We add it to the codebase but later, we may realize its data constructor should be changed.
myProject/main> edit Box
unique type Box = Box Int
We've changed the data constructor from taking a value of typeNat
toInt
.Upon saving the file and runningupdate
again, the UCM will open up the impacted terms in your editor.
myProject/main> update
Okay, I'm searching the branch for code that needs to be
updated...
That's done. Now I'm making sure everything typechecks...
Typechecking failed. I've updated your scratch file with the
definitions that need fixing. Once the file is compiling, try
`update` again.
All impacted terms, including indirect dependents, will be opened in your scratch file.
Box.print : Box ->{IO, Exception} ()
Box.print box = Box.toText box |> printLine
Box.toText : Box -> Text
Box.toText = cases Box nat -> Nat.toText nat
unique type Box = Box Int
The 1st argument to `Nat.toText`
has type: Int
but I expected: Nat
5 | Box.toText = cases Box nat -> Nat.toText nat
6 |
7 | unique type Box = Box Int
The UCM will start printing typechecking errors to the console starting from the top of the file so you know what to tackle first. In our example, the functionBox.print
is opened in the editor even though the change we need to make is in theBox.toText
function. That's because resolving larger, more complicated updates can involve propagating changes to many terms, all the way up the function call chain. With this workflow, you can be assured that your change will leave your codebase in a consistent state. Once all the errors are fixed, you can runupdate
again to commit your changes.
How to update a library dependency
Upgrading a library is very similar to the regular process of updating Unison code. It involves one additional simple command. The following workflow uses Unison's standard library,base
,as an example.
In rare cases, the Unison project that you're depending upon may be located in a user'spublic
namespace, and therefore predates the project ecosystem. In that case, you can usethis process for upgrading.