Hello :wave:
I would like to structure a Roc package in a way that would enable me to call its API as per Example.roc
.
tl;dr Intuitively, A
and B
could be viewed as standard-library interfaces, like Dict
and List
. However, I'd like to have a categorisation "layer" that is Ex
(and such).
# Example.roc
app "example"
packages {
cli: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br",
ex: "./ExamplePackage/main.roc",
}
imports [
cli.Stdout,
ex.Ex.{ B },
]
provides [main] to cli
main =
Stdout.line "Test: $(B.foo {} |> Num.toStr)"
# ExamplePackage/main.roc
package "example-package"
exposes [A, B]
packages {}
# ExamplePackage/Ex/A.roc
# ...
# ExamplePackage/Ex/B.roc
interface Ex.B
exposes [foo, bar]
imports [
A.{ Baz },
]
foo = \{} -> 10
bar = \{} -> 20
# ...
The directory tree looks like the following (package root, e.g., ./ExamplePackage
), but this isn't a constraint (it's rather an attempt to enable me to structure my API and enable it to be utilised as described above):
main.roc # Package main.
Ex/
A.roc
B.roc
I would like to be able to categorise interfaces (eg, C
, D
etc.) into multiple categories like Ex
.
I've attempted multiple iterations to get the working. The best one so far has achieved the following result (via the package structure described above):
imports [
cli.Stdout,
ex.Ex.B,
]
# ...
main =
Stdout.line "Test: $(Ex.B.foo {} |> Num.toStr)"
but this isn't what my actual goal is.
When I attempt to import B
via curly braces, I get an error that Ex.roc
doesn't exist. This is understandable and I believe the issue is to do with my lack of knowledge, in terms of what syntax applies to my use-case. I know I could achieve this via defining A
and B
in Ex.roc
, in order to be able to access them in the desired way. But ideally, I'd like to have them as separate interfaces, because they come with their associated sets of exposed definitions.
Html.Attributes
from the static-site-gen
example seems to be similar enough, but I haven't been able to identify the kind of API access that I'm looking for there.
Thanks!
In your app, does it work if you import B
like ex.Ex.B
instead?
As far as I'm aware what you want (being able to import Ex.{A,B}
) isn't currently possible. I don't see any reason it couldn't be but that syntax just hasn't been implemented.
I ran into this myself recently actually, it's a pain
Is it like the Internal packages, where you need to import it in Ex and then re-expose it?
Well Ex
isn't actually a package, just a path.
If you want to import just A
so you can do A.myFunc
it's not possible. You have to import the full Ex.A
and use the full Ex.A.myFunc
Hi @Luke Boswell
In your app, does it work if you import B like ex.Ex.B instead?
Yes, it does.
Is it like the Internal packages, where you need to import it in Ex and then re-expose it?
Not necessarily. I'd like to utilise Ex
(and other similar "categories") for categorisation.
Thank you for looking into this!
Hi @Eli Dowling,
Yes, that's been my conclusion so far as well. Just wanted to double-check if I'm not missing something.
Thanks for your time, too!
Honestly one could make a strong argument that importing Ex.A
should allow usingA.myFUnc
, and that should you want to useEx.A.myFunc
you should simply import Ex
Agus is working on the module changes. He gave a nice demo in the online meetup, first talk. I'm not sure it specifically addresses this issue, but just thought I'd mention in case you're interested in the new syntax.
There is some chance this will be fixed when module params and the module syntax change is finished.
@Agus Zubiaga Is that possible?
HAahaha well timed :joy:
Lol, https://drive.google.com/file/d/1j2V2CeDN84MjfWPtcLaagQKcCt2qnqum/view?usp=drivesdk
^^ video link
Thank you!
I did listen to the talk (in the background) during work the other day! I'll re-watch it properly to see if it'll enable something that'be closer to the desired use-case.
Hristo has marked this topic as resolved.
Last updated: Jul 06 2025 at 12:14 UTC