Stream: beginners

Topic: How to use effects from platforms in other modules


view this post on Zulip Henrik Larsson (Mar 14 2025 at 16:38):

What is the idiomatic way to use effects from a platform in other modules? I have a module which is called Api where I would like to use the Http effects from the platform. However that effect in only imported in app module. Is the plan that all effects should be passed as arguments if they are to be used in modules?

And lets say I have a function called my_send! in the module Api. If this module is to take the cli.Http.send! function as argument I would have to be able to have this signature in my Api module, Request => Result Response _ but the types Request and Response will not be available either. I am a bit lost here. Looks like all modules should be pure and only the app module should do effects but that is very limiting.

view this post on Zulip Anton (Mar 14 2025 at 17:22):

Is the plan that all effects should be passed as arguments if they are to be used in modules?

Yes, currently. We originally planned to implement "module params" to make this easier but this is no longer in the plans for the new compiler, we now plan to "pass around small stateful values that can have lots of functions on them without needing to carry around a ton of closures at runtime, and still be used concisely", I presume with help from static dispatch (not implemented yet) :thinking:

view this post on Zulip Henrik Larsson (Mar 14 2025 at 17:26):

@Anton But how do you solve the type issue, the modules would still have to have access to Request, Response types. If I for example have an Api struct that would be defined in the Api module and on the Api struct I have a key called send!, then I would have to use the type signature Request => Response but I will not have access to the types?

view this post on Zulip Anton (Mar 14 2025 at 17:29):

We originally planned to implement "module params"

I forgot we did implement module params, this is probably a helpful example.

view this post on Zulip Anton (Mar 14 2025 at 17:30):

But how do you solve the type issue

let me think about that...

view this post on Zulip Anton (Mar 14 2025 at 17:58):

@Ian McLerran (in roc-ai) re-created his own identical type, it contains all the same fields as InternalHttp.Response. I think there may not be a more convenient solution for now.

view this post on Zulip Anton (Mar 14 2025 at 17:59):

@Agus Zubiaga may know more

view this post on Zulip Henrik Larsson (Mar 14 2025 at 18:37):

For Request and Response that works but for example in Tcp.connect! which has a Stream type that is an Opaque type. So the connect function would still cause issues then.

view this post on Zulip Anton (Mar 14 2025 at 18:46):

We may also be using structural equality for opaque types, so it could work but yeah, I'm not sure

view this post on Zulip Anton (Mar 14 2025 at 18:46):

Let me check

view this post on Zulip Anton (Mar 14 2025 at 18:52):

No, it doesn't work

view this post on Zulip Anton (Mar 14 2025 at 19:01):

In the original module params proposal it looks like the opaque types could be imported:

this means all Roc modules become architecturally platform-agnostic by default; the only way to couple them to a specific platform would be by using an effect or opaque type which only that platform offers.

view this post on Zulip Henrik Larsson (Mar 14 2025 at 19:02):

I just realized that the same problem is for all external dependencies. For example if I depend on roc-json and I want to use Json.utf8 in some other module I need to send that as a parameter. This will be interesting to see how this will evolve since having to send even pure dependencies as parameters on objects (since I have heard that module parameters will be removed) feels messy already in my small code example.

view this post on Zulip Anton (Mar 14 2025 at 19:04):

Yeah, looks like you can just import that :sweat_smile:
https://github.com/imclerran/roc-ai/blob/3d4e7f1a4a41799bbbb12561ecc2074508200b11/package/Chat.roc#L18

view this post on Zulip Anton (Mar 14 2025 at 19:05):

Forgot to think of the obvious solution :p

view this post on Zulip Henrik Larsson (Mar 14 2025 at 19:10):

Interesting, I am getting an error when trying that but I think it has to do with my project layout.

Do you know how I can use a local platform for my project, currently I am just using the examples folder in basic-cli platform but that is not so nice, I would like to have a local build of basic-cli and import that in my roc project. However when I try to import from my external project the same way as is done in examples pf: platform "<path-to-basic-cli>/platform/main.roc" this just fails.

view this post on Zulip Anton (Mar 14 2025 at 19:54):

I think you need to do the following in your local basic cli folder dirst:

view this post on Zulip Anton (Mar 14 2025 at 19:54):

./jump-start.sh
roc build.roc --linker=legacy

view this post on Zulip Anton (Mar 14 2025 at 19:56):

Can you share the error?

view this post on Zulip Anton (Mar 14 2025 at 19:59):

Anton said:

Forgot to think of the obvious solution :p

Your original question immediately made me think of module params

view this post on Zulip Henrik Larsson (Mar 14 2025 at 20:20):

Now I got the platform import working, not sure what was wrong before.

view this post on Zulip Henrik Larsson (Mar 14 2025 at 20:22):

Haha yes, it was a very nice discussion, I guess the module params and the sending effects as params are nice patterns for testing your code. But now I am able to import both platform effects and other third part dependency into any module in my project with just
import cli.Stdout or json.Json


Last updated: Jul 06 2025 at 12:14 UTC