unisonweb / unisonweb-org

Source for the unisonweb.org website
https://unisonweb.org
Other
40 stars 61 forks source link

Error in the stream example of the abilities section #286

Open maxtremblay opened 3 years ago

maxtremblay commented 3 years ago

While reading the Abilities in Unison section, I tried to run the following example:

structural ability Stream e where
  emit : e ->{Stream e} ()
  -- equivalently
  -- emit : e -> ()

Stream.range : Nat ->{} Nat ->{Stream Nat} ()
Stream.range n m =
  if n >= m then ()
  else
    emit n
    Stream.range (n + 1) m

However, I got the following error

The else clause of an if expression needs to
  have the same type as the then clause.

  Here, one   is:  Unit
  and another is:  Unit ->{Stream Nat} Unit

      8 |   if n >= m then ()
      9 |   else
     10 |     emit n
     11 |     Stream.range (n + 1) m

From the error message, I figured out I can replace the last line of the range definition by

Stream.range (n + 1) m ()

but this seems weird to me.

In case this is helpful, I am running release/M2j (built on 2021-10-07).

ceedubs commented 3 years ago

@maxtremblay for me (also on release/M2j) I can't reproduce this locally , but I suspect that I know what's going on.

Do you have all of this code within the same scratch file and are adding it all at once? When I do this it works as expected.

But what I think is happening is that your else clause is somehow picking up .base.Stream.range, which is defined as:

.base.Stream.range : Nat -> Nat -> '{Stream Nat} ()
.base.Stream.range n m _ = Stream.range! n m

This would explain why it's expecting you to force the delayed thunk with (). What isn't clear to me is why it would pick up the Stream.range from base instead of the one that you are declaring. If you are able to create a transcript that reproduces this issue, that would be very helpful!

maxtremblay commented 3 years ago

There it is.

transcript.md

ceedubs commented 3 years ago

@maxtremblay thank you! I now see the behavior that you were talking about.

If I remove the use .base then it works just fine. But the Stream.range that's being defined should be prioritized over the one coming from .base. So this does seem like a bug, and worse, one that users can run into while going through the intro docs. @pchiusano or @runarorama do either of you know what's going on here?