Don’t think of let
as “assigning” a value (although it does do that), but think of it as destructuring a pattern. For example, you’re probably familiar with this: let {a, b} = ...
which destructures a record and assigns its fields to bindings a
and b
. You can actually do the same thing with any kind of pattern, including variants:
type t = A(int) | B(int)
let A(x) | B(x) = foo
This will bind an int
to the name x
. Note that this is only possible if the patterns after let
are exhaustive and contain all of the same variable names with the same types. Basically, it’s like syntax sugar for this:
type t = A(int) | B(int)
switch foo {
| A(x) | B(x) => ...
}
With this in mind, consider that unit
is technically just a variant with a single constructor, ()
. That means you can “destructure” it like any variant. In fact, we can make our own "unit’ type and use it exactly the same way:
type t = Unit
let ignore = _ => Unit
let Unit = ignore(1)
Although note that let () = ...
is not usually necessary, since the ReScript compiler allows statements that return unit
to not need a let
. (OCaml, which ReScript is forked from, is stricter and requires it.) But sometimes people use let () = ...
anyway just to be explicit.
Since all files are compiled as top-level modules, it’s common to prefix them as a kind of namespace if you have a lot of similar modules.
It’s hard to say why without seeing the actual function. Usually there’s a specific reason for it. The most common reason is that the function has optional named arguments (~arg=?
). The compiler needs a positional argument to know when the function is fully applied and when it’s being curried. A final unit argument is conventional for that.
I’m not sure if there’s a built-in way to pass around JS constructors, but you can make a quick-and-dirty external:
type js_string
@val external js_string: js_string = "String"
let x = js_string
Someone else may have a more elegant solution, though.
There’s no bulletproof way, unfortunately. Sometimes the typechecker will alert you. For example, if it says it expected type int
but received type string => int
then that indicates that you forgot to apply a string
argument. However, there are cases where that doesn’t get covered. Again, someone else may have more advice about this.