Could I pass Types defined in interface to be seen in other files ? What is the syntax for that?
Hi! Yes you can do that!
In your interface file:
interface SomeInterface
exposes [SomeType]
imports []
SomeType : [SomeTag]
in the file you wish to use it you just need to specify in the imports
section what you want to use
imports [SomeInterface.{SomeType}]
...
value : SomeType
value = SomeTag
Although you can qualify the type when you use it instead
imports [SomeInterface]
...
value : SomeInterface.SomeType
value = SomeTag
You can also hide the implementation using opaque types, which you can read more about in the docs-
https://www.roc-lang.org/tutorial#opaque-types
hope that helped!
btw. could you produce example of that
You can prevent that data needs to be checked multiple times. For example, you can create an opaque NonEmptyList from a List after you've checked it. Now all functions that you pass this NonEmptyList to do not need to handle the empty list case.
I don't get it
It's about implementation hiding-
if you've ever used an OO language like Java / C# you would use an opaque type for the same reason you use private variables.
In Elm it would be like exposing SomeType
instead of SomeType(..)
.
The point of an opaque type is that you can only examine it's internals within the file that created it. So if I want to do something with a non-empty list value, I could create an opaque type which can only be interfaced with in safe ways by guaranteeing that the list is never empty, even though a NonEmptyList type would be internally represented as a List.
Elm has a nonempty list package that you could copy in Roc. With a package like that you can use the fromList
function at the start to check if your list is empty. If it's not, you now have a NonEmpty
(=list). You can now get for example the last element, and that function is guaranteed to return an element, so you no longer need to deal with a Result
type for the empty list case.
I wonder if there's a way to generalise that pattern? There's lots of functions that can error purely because of some degenerate case, where it would be more useful to rule out from the start rather than check at every stage.
Dependent types is one solution, but that's also complex to implement.
I think some long conversation has been had about that, so I knew that was a possibility. If I remember, the answer was a resounding "maybe, possibly, someday, if a bunch of problems it'd cause could be solved, but not now". I was just curious if there were some trick that wouldn't require altering the type system.
there's a trick involving a type variable trick similar to what we do with Num
e.g. something like this:
List elem emptiness := ...
PotentiallyEmptyList elem : BaseList elem [CouldBeEmpty]
NonEmptyList elem emptiness : List elem emptiness
but I don't like what that would do to the ergonomics of lists :big_smile:
Maybe it'd be worth figuring out if there'd be a way to make that ergonomic in the future, because it'd certainly be useful. But that sounds like a future-if-ever-problem.
Anton said:
Elm has a nonempty list package that you could copy in Roc. With a package like that you can use the
fromList
function at the start to check if your list is empty. If it's not, you now have aNonEmpty
(=list). You can now get for example the last element, and that function is guaranteed to return an element, so you no longer need to deal with aResult
type for the empty list case.
I started implementing a type like this. Still a work in progress though: https://github.com/Subtlesplendor/roc-data/blob/main/package/NonEmpty.roc
Last updated: Jul 05 2025 at 12:14 UTC