Hi. 😀 We welcome you to contribute to the Unison base libraries. This library follows the conventions in this document and we recommend reading that document, in particular this section on creating and managing pull requests.
The base
library has no external dependencies, so its namespace looks like:
trunk/
List/
Nat/
releases/
_M1j/
_M1k/
...
You'll be pulling trunk
of this repo into your local namespace, forking it to make some changes, pushing the updated version of trunk to some public Unison repo, then using the pull-request.create
command to create the PR.
.> pull https://github.com/unisonweb/base:.trunk _base
(you can do this both for initial fetch and for subsequent updates).> fork _base .prs.base._mything
to create a copy of_base
. You can create multiple forks in.prs.base
, if you have multiple things you're working on.- If you haven't already done so, set your default author, and for at least
.prs.base
set the default license to MIT, which is the preferred license for new definitions in this repo (if you're already using the MIT license as your default license everywhere, then no action needed). See these instructions on how to configure just a sub-namespace with a different license and there's a sample excerpt config below. - Now
cd .prs.base._mything
and hack away. You can at any time review what's changed between your namespace and_base
withdiff.namespace ._base .prs.base._mything
. - Push your forked version somewhere public. Suggestion: just mirror your root Unison namespace to a git repo
.> push git@github.com:mygithubname/allmyunisoncode
. No need to maintain a separate Git repo for every Unison library you want to contribute to. .prs.base._mything> pull-request.create https://github.com/unisonweb/base:.trunk https://github.com/myuser/allmyunisoncode:.prs.base._mything
and this will create some output. Copy that output to your clipboard. We don't literally use the GitHub pull request mechanism for Unison repositories, we use GitHub issues instead.- Next, create a GitHub issue in this repo (that's right, an issue, not a GitHub PR). Make the issue title something descriptive, and for the issue body, paste in the output generated by
pull-request.create
as well as some text describing the change, just like you would for any other pull request. - Use the GitHub issue comments for coordinating the review. Once merged, the maintainer will close the issue.
See these instructions but to set the license for prs.base
, your config will look something like:
DefaultMetadata {
prs.base = [".metadata.licenses.myauthorname_mit_2020"]
}
For a definition (we'll use List.map
as an example), here's where to put the documentation, tests, and examples:
List.map.doc
is the primary documentation. It should be linked toList.map
using thelink
command as described here. This ensures that the user can view these docs usingdocs List.map
.List.map.docs.whyListIsTheBest
,List.map.docs.basicListProcessing
are any supporting documentation.- Suggestion: within the primary documentation, you can link to other documentation!
List.map.examples.ex1
orList.map.examples.moreDescriptiveName
are examples (which might be used by the documentation).List.map.tests.ex1
,List.map.tests.someBetterName
are named tests forList.map
.
We put the docs, examples, and tests right next to the corresponding definitions for a couple of reasons:
- It plays well with suffix-based name resolution since the tests, examples, and docs don't share a suffix with the original definition.
- It's a bit easier to do slicing and dicing of libraries when the definitions and their tests and examples are all together under a single namespace.
This isn't a complete list, but here are some ideas for contributions you can make:
- Documentation and/or tests or examples for existing definitions
- New definitions... like maybe add your favorite missing function on
List
- Add a new data structure!
- Add some interesting functions that work with abilities. For instance, see the
Stream
namespace.
Unlike other languages, where changing the standard library involves everyone downstream enduring a tedious upgrade cycle, definitions in Unison never change and are always valid once they are created. If we change the naming conventions or shuffle definitions around later, that's no big deal and doesn't break anyone's code. It's also not a problem for definitions to start out here in base and perhaps later get broken out into separate libraries--none of the downstream code which obtained the definitions from here originally will break.
We hope this also means there's less need for bikeshedding about small details, because changing small things like naming and organization later is easy.
At this time, there is a restriction on having operators be part of namespaces. To circumvent this limitation, after creating your function and adding documentation and examples, alias the function with the operator name of your choice.
inc : Nat -> Nat
inc x = x + 1
inc.doc = [:
`inc` increments a Nat.
It exists as a workaround for the `++` operator.
:]
Then in the codemanager:
.> link inc.doc inc
Updates:
1. inc : Nat -> Nat
+ 2. doc : Doc
.> alias.term inc .some.namespace.(++)
Done.
Currently, if you've already linked documentation to a definition, updating that documentation doesn't unlink the old docs and link in the new version, so you have to do that manually. Not great. See this issue.
Until this issue is fixed, you might want to hold off on linking documentation to the definitions until you're pretty happy with it.