1. 15
    1. 4

      For anyone who hasn’t used Unison’s library documentation before, you’re in for a treat:

      on the home page, if you click on the @stew / http package, you’ll be taken to the readme for the package - pretty standard so far. Clicking on HttpRequest.get will then go to get‘s documentation, but for some reason it’s kinda small, with a button to reveal more. Where things get fun is if your then click on HttpRequest, you’ll see it’s documentation pop up at the top of the page, but get‘s docs are still there below; click Body and you’ll then get its documentation pushed to the top of the stack.

      This is probably what most of us do with browser tabs all the time, but being able to basically dynamically create your own page of docs for the types and functions you’re trying to use, and have it all visible at once, it such a time saver.

    2. 1


      Infix notation without operator precedence seems like a tremendously bad idea. If they didn’t want to implement operator precedence, why not use prefix notation?

    3. 1

      It’s hard to look at this page without seeing all of the names. As I understand it, Unison’s types and packages have names, and isomorphic types are only equivalent if they have the same name. How can Unison hope to offer a better experience than Haskell or OCaml when it still has these structural issues?

      1. 4

        isomorphic types are only equivalent if they have the same name

        That’s not true. Unison has two forms of types, the common one is a structural type and that means structural equivalent types are hashed to the same thing. For example:

        structural type Optional a = None | Some a
        structural type Maybe x = None | Just x

        These are hashed to the same underlying type. Unison doesn’t put a limit on how many names you can give a hash though, so if you defined the above, you could use either Optional or Maybe, depending on what you’ve defined/imported.

        Alternatively, you can use a unique type to prevent things from hashing to the same type. For example:

        unique type Suit = Hearts | Spades | Diamonds | Clubs
        unique type Direction = North | South | East | West

        So you can’t accidentally use a South when you meant a Spades.

        1. 3

          out of curiosity, what happens if I declare:

          structural type Foo = A | B | C Int
          structural type Bar = B | A | C Int

          Does Foo::A (made up syntax) equal Bar::B?

          1. 1

            Open up ucm, make a file (e.g. scratch.u) with this content:

            structural type Foo = A | B | C Int
            structural type Bar = B | A | C Int
            isBarB : Bar -> Boolean
            isBarB bar =
              match bar with
                Bar.B -> true
                _ -> false
            > isBarB Foo.A

            Save it and Unison will tell you:

              Now evaluating any watch expressions (lines starting with `>`)... Ctrl+C cancels.
                10 | > isBarB Foo.A
            1. 2

              I’ve realised an easier way to test this is in ucm:

              .> display Foo.A 

              Which is interesting behaviour. I’m not sure how Unison selects which definition to use for displaying.

        2. 1

          Thank you for correcting me. Are packages also structural, or are packages unique?

          1. 2

            Types are hashed independent of the package. If I define Boolean myself, it would have the same hash as base’s Boolean. I could write a function which works on “both” (because there is no both, really)

      2. 1

        I don’t use Unison, but I didn’t understand some of this. What does “all of the names” refer to in this context? I’m also unsure what “isomorphic” means here.

        Could you elaborate?

        1. 1

          Suppose that there is only one way to implement a particular type and its associated functionality. (Maybe there are multiple ways, but only one way that fits some code-style requirements.) Then there clearly is no need for multiple packages implementing that type. So, what is the point of all of the different named packages, then?