Stream: beginners

Topic: ✔ Curious if this works in Roc?


view this post on Zulip osa1 (Jun 14 2024 at 12:47):

Hi. I'm curious if Roc equivalent of this OCaml code works in Roc. I wanted to try it myself, but I'm unable to run anything. ("missing header" or something like that)

type ('ok, 'err) result =
  | Ok of 'ok
  | Err of 'err

let handle (x : (int, [`A | `B | `C | `D]) result) : (int, [`B | `D]) result =
  match x with
  | Err(`A) -> Ok(1)
  | Err(`C) -> Ok(2)
  | other -> other (* doesn't work, `other` has the same type as `x` *)

As far as I understand tags in Roc are the same in polymorphic variants in OCaml. I'm wondering if this kind of thing ports directly to Roc, and whether it has the same limitation as OCaml.

view this post on Zulip Anton (Jun 14 2024 at 13:16):

For the "missing header" I suspect that you need an app header like in helloWorld. When writing a Roc program I usually start from helloWorld.roc.

view this post on Zulip Anton (Jun 14 2024 at 13:20):

I'll look into improving that error because it is almost impossible for a beginner to create a working program with only the info provided in that error message.

view this post on Zulip Anton (Jun 14 2024 at 13:27):

https://github.com/roc-lang/examples/issues/182

view this post on Zulip Anton (Jun 14 2024 at 13:39):

Yeah, we hit the same problem as in OCaml:

app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }

import pf.Stdout
import pf.Task

main =
    Stdout.line! "Hello, World!"

ErrType : [A, B, C, D]

handle : [Ok U64, Err ErrType] -> [Ok U64, Err [B, D]]
handle = \x ->
    when x is
        Err A -> Ok 1
        Err C -> Ok 2
        other -> other

Error message:

── TYPE MISMATCH in examples/helloWorld.roc ────────────────────────────────────

Something is off with the body of the handle definition:

11│   handle : [Ok U64, Err ErrType] -> [Ok U64, Err [B, D]]
12│   handle = \x ->
13│>      when x is
14│>          Err A -> Ok 1
15│>          Err C -> Ok 2
16│>          other -> other

This when expression produces:

    [Err [
        A,
        B,
        C,
        D,
    ], …]

But the type annotation on handle says it should be:

    [Err [
        B,
        D,
    ], …]

────────────────────────────────────────────────────────────────────────────────

It's possible that we improve this in the future but I don't know how complicated the required compiler changes would be.

view this post on Zulip Norbert Hajagos (Jun 14 2024 at 14:02):

Wait, I don't understand... Why is this code incorrect?

view this post on Zulip Anton (Jun 14 2024 at 14:07):

Yeah well it's definitely something that could work but the compiler is currently not "smart" enough to figure that out.

view this post on Zulip Norbert Hajagos (Jun 14 2024 at 14:16):

Okay, thanks

view this post on Zulip osa1 (Jun 14 2024 at 15:24):

Thanks for the answer.

view this post on Zulip Notification Bot (Jun 14 2024 at 15:25):

osa1 has marked this topic as resolved.

view this post on Zulip osa1 (Jun 14 2024 at 15:27):

It's possible that we improve this in the future

@Anton Do you mean you know how to improve the type checker or inference algorithm to make this work, or are you guessing that it may be possible?

I'm curious how you would go about improving this. I don't know too much about Roc's type system, but I'm assuming some kind of constraint-based HM formulation, with unification for solving the constraints, and row types. I'm curious how you would make this work in such a system if you already know.

view this post on Zulip Anton (Jun 14 2024 at 15:50):

I'm guessing that it is possible. @Ayaz Hafiz will probably know this.

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 15:54):

Roc does not have gradual types

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 15:55):

This should not work (maybe it will change one day, bit I don't think there are any plans currently)

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 15:55):

The type of other is the same type as x

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 15:57):

That code is equivalent to doing:

ErrType : [A, B, C, D]

handle : [Ok U64, Err ErrType] -> [Ok U64, Err [B, D]]
handle = \x ->
    when x is
        Err A -> Ok 1
        Err C -> Ok 2
        _ -> x

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 15:59):

x is a [Ok I64, Err ErrType] so returning x must also return a [Ok I64, Err ErrType]. It is still the same type, it just won't contain an Err A or Err C at runtime.

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 16:01):

To fix it you would have to manually speed out the different variants to avoid returning x. That might be a sugar worth adding to when ... is explicitly.

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 16:02):

ErrType : [A, B, C, D]

handle : [Ok U64, Err ErrType] -> [Ok U64, Err [B, D]]
handle = \x ->
    when x is
        Err A -> Ok 1
        Err C -> Ok 2
        Err B -> Err B
        Err D -> Err D
        Ok v -> Ok v

view this post on Zulip osa1 (Jun 14 2024 at 17:02):

I don't know what this kind of typing would be called but I'm pretty sure it has nothing to do with gradual typing, which is about mixing dynamic and static typing (see wiki page).

view this post on Zulip Richard Feldman (Jun 14 2024 at 17:05):

Ayaz has a plan to fix this

view this post on Zulip Richard Feldman (Jun 14 2024 at 17:05):

I forget where it’s tracked

view this post on Zulip Richard Feldman (Jun 14 2024 at 17:06):

it doesn’t require gradual typing - it’s about the pattern match in the branch affecting the type of the branch body based on the other branches, plus needing to silently convert from one in-memory representation to another in that branch

view this post on Zulip Richard Feldman (Jun 14 2024 at 17:07):

but yeah we definitely want this to work as described!

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 17:08):

Sorry, I think it may be refinement types or something.....too many names

view this post on Zulip Richard Feldman (Jun 14 2024 at 17:08):

“Type refinement” I think might have been the name Ayaz used

view this post on Zulip Richard Feldman (Jun 14 2024 at 17:09):

or “narrowing” maybe

view this post on Zulip Brendan Hansknecht (Jun 14 2024 at 17:09):

And yeah, we could make this automatic/implicit (which sounds like what is planned). Personally, I would rather it be explicit causing implicit means unexpected data movement. But this is probably a case where convenience outweighs any performance concerns.

view this post on Zulip osa1 (Jun 14 2024 at 17:15):

Thanks. If anyone knows where this is tracked I would be happy to follow :grinning:

view this post on Zulip Anton (Jun 14 2024 at 17:59):

Found it :)


Last updated: Jul 06 2025 at 12:14 UTC