I'm trying to add hosted functionality to clear the terminal (using the CLI example as a base). I'm able to get it working by modifying Effect.roc
and lib.rs
, but I'm having trouble when trying to implement it in a new "Terminal" module instead. Here's my Terminal.roc
:
hosted Terminal
exposes [ clear ]
imports [ pf.Effect, Task.{ Task } ]
generates Terminal with []
clearTerminal : {} -> Effect.Effect {}
clear : {} -> Task {} *
clear = \{} -> Effect.map (clearTerminal {}) (\_ -> Ok {})
and here's the error I'm getting:
[nix-shell:~/roc]$ roc check /mnt/d/Home/roctest/test.roc
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
Something is off with the body of the clearTerminal definition:
1│ hosted Terminal
This Terminal private tag application has the type:
[ Terminal ({}a -> b) ]d
But the type annotation on clearTerminal says it should be:
[ Effect.Effect ({} -> {}) ]
Tip: Seems like a tag typo. Maybe Terminal should be Effect.Effect?
Tip: Can more type annotations be added? Type annotations always help
me give more specific messages, and I think they could help a lot in
this case
────────────────────────────────────────────────────────────────────────────────
Hosted is new to me (and roc in general?), but I would guess the issue is that hosted is just for effects. Instead, you probably want terminal to be more akin to the Stdout module. It wraps an effect.
There aren't currently any effects for clearing the terminal, setting the cursor position in the terminal, etc. I need to add those, which requires adding some functionality in rust that can be called from roc. I can do this by modifying Effect, but I was hoping there might be a way to add another hosted module.
I am pretty sure that all effects must be exposed through the effect module. They then can be imported and wrapped in other modules. So you would add an effect for clearing the terminal, but give it a nicer exposed wrapper in the terminal module.
Effect is essentially the cffi specification
You probably want to do
interface Terminal
exposes [ clear ]
imports [ pf.Effect, Task.{ Task } ]
clearTerminal : {} -> Effect.Effect {}
clear : {} -> Task {} *
clear = \{} -> Effect.map (clearTerminal {}) (\_ -> Ok {})
hosted
generates a new Effect
implementation
Is that going to allow me to implement clearTerminal in rust?
I see, sorry, I misunderstood. Indeed it won't.
You could create a new hosted module that has Terminal
as the effect name, but the problem is that it won't work with Task
as Task
is defined currently. That's because Task
in the CLI platform wants the Effect
type alias from the Effect
module, but effects produced in the new hosted Terminal
module would have to produce Terminal
effects. So something like
hosted Terminal
exposes [ clear ]
imports [ pf.Effect, Task.{ Task } ]
generates Terminal with [map]
clearTerminal : {} -> Terminal {}
clear : {} -> Terminal (Result {} *)
clear = \{} -> Terminal.map (clearTerminal {}) (\_ -> Ok {})
should work
Why not write all the rust wrapper functions in the effect module? That is what it is made for.
So Effect is the ffi module. Then Stdin, Stdout, Terminal, File, etc are the exposed modules with nice interfaces for the app to use.
They just end up delegating to an effect.
@Jared Cone might be easier to pair on it - dm me if you'd like to!
Will do. Yea could definitely just define everything in Effect, I was just thinking that might grow quite large if it's going to house all the functionality for terminal, filesystem, networking, etc
if the terminal supports ANSI escape codes you can use Stdout.line
to move cursor, scroll, erase, etc... Not quite a console api, but something that can be useful in the meantime :)
Last updated: Jul 05 2025 at 12:14 UTC