1---
2name: scripting-with-roc
3description: Creates Roc scripts for CLI automation with strong static types, helpful compiler errors, and functional programming. Use when the user wants Roc scripts, mentions Roc, functional scripting, type-safe scripts, strongly-typed scripts, or needs executable .roc files.
4license: AGPL-3.0-or-later
5metadata:
6 author: Amolith <amolith@secluded.site>
7---
8
9Create scripts using Roc, a functional language with strong types, helpful compiler errors, and no runtime. Scripts can run with `roc` or compile to standalone binaries.
10
11**Platform version note**: Examples use basic-cli 0.20.0. Check https://github.com/roc-lang/basic-cli/releases for the latest version and update URLs accordingly.
12
13## Reference documentation
14
15- **Tutorial**: See [llms.txt](references/llms.txt) for comprehensive language guide
16- **Standard library**: See [builtins-llms.txt](references/builtins-llms.txt) for all builtin modules
17
18## Basic structure
19
20Every Roc CLI script needs:
21
221. Shebang line (use `/usr/bin/env roc` or full path to roc)
232. App header declaring the platform
243. Imports from platform
254. Main function with effectful signature
26
27```roc
28#!/usr/bin/env roc
29app [main!] { cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.20.0/X73hGh05nNTkDHU06FHC0YfFaQB1pimX7gncRcao5mU.tar.br" }
30
31import cli.Stdout
32
33main! = |_args|
34 Stdout.line!("Hello, World!")
35```
36
37Make executable: `chmod +x script.roc`, then run: `./script.roc`
38
39If `roc` is not in PATH, use full path in shebang: `#!/home/user/.local/share/roc/current/roc`
40
41## Command-line arguments
42
43```roc
44#!/usr/bin/env roc
45app [main!] {
46 cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.20.0/X73hGh05nNTkDHU06FHC0YfFaQB1pimX7gncRcao5mU.tar.br",
47}
48
49import cli.Stdout
50import cli.Arg exposing [Arg]
51
52main! : List Arg => Result {} _
53main! = |raw_args|
54 args = List.map(raw_args, Arg.display)
55
56 # Index 0 is executable path, 1 is first real argument
57 when List.get(args, 1) is
58 Err(_) ->
59 Err(Exit(1, "Error: Expected one argument\n\tUsage: ./script.roc <input>"))
60
61 Ok(first_arg) ->
62 Stdout.line!("Received: ${first_arg}")
63```
64
65## Code quality tools
66
67Roc provides helpful tooling for maintaining code quality. Use these regularly:
68
69### Format code
70
71```bash
72roc format script.roc
73```
74
75Automatically fixes spacing, indentation, and formatting. Run before committing code.
76
77### Type check
78
79```bash
80roc check script.roc
81```
82
83Checks types and reports errors/warnings without executing. Catches:
84- Type mismatches
85- Unused definitions
86- Unused arguments (suggests prefixing with `_`)
87- Missing pattern matches
88
89Example warnings:
90```
91── UNUSED DEFINITION in script.roc ──────────────────────────────────────
92unused_var is not used anywhere in your code.
9312│ unused_var = 42
94 ^^^^^^^^^^
95```
96
97### Run tests
98
99```bash
100roc test script.roc
101```
102
103Runs all `expect` expressions. Example:
104
105```roc
106add = |a, b| a + b
107
108expect add(2, 3) == 5
109expect add(0, 0) == 0
110```
111
112Warnings appear during script execution but don't prevent running. Fix them for clean code.
113
114## Common patterns
115
116### Reading stdin
117
118```roc
119app [main!] { cli: platform "..." }
120
121import cli.Stdin
122import cli.Stdout
123
124main! = |_args|
125 input = Stdin.line!
126 Stdout.line!("You entered: ${input}")
127```
128
129### File operations
130
131```roc
132app [main!] { cli: platform "..." }
133
134import cli.File
135import cli.Path
136import cli.Stdout
137
138main! = |_args|
139 path = Path.from_str("input.txt")
140 content = File.read_utf8!(path)?
141
142 Stdout.line!("File content: ${content}")
143```
144
145### Error handling
146
147Roc uses `Result` types, not exceptions. Use `?` to short-circuit on errors:
148
149```roc
150main! = |_args|
151 path = Path.from_str("config.json")
152 content = File.read_utf8!(path)? # Returns early if error
153
154 # Process content...
155 Stdout.line!("Success!")
156```
157
158Or explicit pattern matching:
159
160```roc
161main! = |_args|
162 result = File.read_utf8!(Path.from_str("file.txt"))
163
164 when result is
165 Ok(content) -> Stdout.line!("Read: ${content}")
166 Err(err) -> Err(Exit(1, "Failed: ${Inspect.to_str(err)}"))
167```
168
169### Working with lists
170
171```roc
172# Filter, map, fold
173numbers = [1, 2, 3, 4, 5]
174evens = List.keep_if(numbers, |n| n % 2 == 0)
175doubled = List.map(evens, |n| n * 2)
176sum = List.walk(doubled, 0, Num.add)
177```
178
179### String manipulation
180
181```roc
182# Concatenation, splitting, trimming
183text = Str.concat("Hello", " World")
184words = Str.split(text, " ")
185trimmed = Str.trim(" spaces ")
186replaced = Str.replace_each(text, "World", "Roc")
187```
188
189## Type signatures
190
191Add type signatures for clarity (optional but helpful):
192
193```roc
194process_file : Str => Result Str [FileNotFound, InvalidUtf8]
195process_file = |filename|
196 path = Path.from_str(filename)
197 content = File.read_utf8!(path)?
198 Ok(Str.to_upper(content))
199
200main! : List Arg => Result {} _
201main! = |args|
202 when List.get(args, 1) is
203 Ok(filename) ->
204 result = process_file!(filename)
205 when result is
206 Ok(content) -> Stdout.line!(content)
207 Err(_) -> Err(Exit(1, "Failed to process file"))
208
209 Err(_) ->
210 Err(Exit(1, "Usage: roc script.roc <filename>"))
211```
212
213## Important notes
214
215- **Platform URL**: Use current basic-cli release from https://github.com/roc-lang/basic-cli/releases
216- **No runtime**: Compiled binaries are standalone
217- **Immutable**: All values immutable; operations return new values
218- **Type inference**: Types inferred but signatures help clarity
219- **Helpful errors**: Compiler provides detailed, friendly error messages
220- **No exceptions**: Use `Result` for errors; no try/catch
221- **Functional**: Functions are first-class; use `|param| expression` syntax
222
223## Platform imports
224
225Common modules from `cli` platform:
226
227- `cli.Stdout` - Write to stdout
228- `cli.Stdin` - Read from stdin
229- `cli.File` - File operations
230- `cli.Path` - Path handling
231- `cli.Arg` - Command-line arguments
232- `cli.Env` - Environment variables
233- `cli.Dir` - Directory operations
234
235## When to use Roc
236
237**Good for:**
238- Type-safe scripts that catch errors at compile time
239- Functional programming enthusiasts
240- Long-lived scripts benefiting from stability
241- Learning functional programming
242- No dependencies needed (strong stdlib)
243
244**Avoid for:**
245- Production-critical code (Roc pre-1.0, breaking changes possible)
246- When you need mature ecosystem/libraries
247- Quick throwaway scripts (compilation overhead)
248- When team doesn't know functional programming
249
250## Maturity caveat
251
252Roc lacks numbered releases (still alpha/pre-1.0). Core features work well, but expect:
253- Breaking changes between versions
254- Some missing features
255- Smaller community/fewer examples
256- Excellent for learning and experimentation, use production caution