Releases: roc-lang/roc
0.0.0-alpha2-*
Note: we're starting with a new release approach. Each time a breaking change happens, the alpha number will be incremented in 0.0.0-alpha. The *
indicates a rolling release, the tar.gz archives in assets will be updated if the changes are non-breaking. So upgrading to the latest tar.gz with the same alpha should not create any problems.
We recommend these alpha releases for most users instead of the nightly releases.
❗ if your project used a latest nightly url like:
https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-latest.tar.gz
You should probably switch it to:
https://github.com/roc-lang/roc/releases/download/0.0.0-alpha2-rolling/roc-linux_x86_64-0-alpha2-rolling.tar.gz
Migration guide
TL;DR
- Run
roc format --migrate
to upgrade most syntax changes - Replace usages of
Task
witheffectful!
functions - Use
Result.map_ok
instead ofResult.map
Str.BadUtf8
has changed fromBadUtf8 Utf8ByteProblem U64
toBadUtf8 { problem: Utf8Problem, index: U64}
What changed?
Since the last update, Roc has gone through lots of syntax changes! We want
to make Roc a friendly language for new programmers, functional programming wizards,
and everyone in between. To that end, we've made Roc look more like mainstream
languages while still keeping things clean and concise.
Let's look at a sample application to see what changed:
app [main] { pf: platform "<basic-cli>" }
import pf.File
import pf.Stdout
main =
readmePath = "./README.md"
licensePath = "./LICENSE"
when checkContentsOfFiles readmePath licensePath |> Task.result! is
Ok {} -> Task.ok {}
Err err ->
msg =
when err is
FileReadErr _ -> "Error reading README"
FailedToReadLicense -> "Failed to read LICENSE file"
Task.err (Exit 1 "unable to read file: $(msg)")
checkContentsOfFiles : Str, Str -> Task {} _
checkContentsOfFiles = \readmePath, licensePath ->
readmeContents = File.readUtf8! readmePath
licenseContents = File.readUtf8 licensePath
|> Task.mapErr! \_ -> FailedToReadLicense
readmeLines = Str.split readmeContents "\n"
firstReadmeLine = List.first lines |> Result.withDefault "<empty README>"
licenseLength = Str.split license "\n" |> List.len
Stdout.line! "First line of $(readmePath): $(firstReadmeLine)"
Stdout.line! "Line count for $(licensePath): $(Num.toStr licenseLength)"
This example reads the README and the LICENSE of a repository and prints some info on
it, namely the first line of the README and the number of lines in the LICENSE. Let's
look at its modern counterpart!
app [main] { pf: platform "<basic-cli>" }
import pf.File
import pf.Stdout
main! = |_args|
readme_path = "./README.md"
license_path = "./LICENSE"
check_contents_of_files(readme_path, license_path)
|> Result.map_err!(|err|
msg =
when err is
FileReadErr(_) -> "Error reading README"
FailedToReadLicense -> "Failed to read LICENSE file"
Err(Exit(1, "unable to read file: ${msg}")))
check_contents_of_files! : Str, Str => Result {} _
check_contents_of_files! = |readme_path, license_path|
readme_contents = File.read_utf8!(readme_path)?
license_contents = File.read_utf8(license_path) ? |_| FailedToReadLicense
readme_lines = Str.split(readme_contents, "\n")
first_readme_line = List.first(lines) ?? "<empty README>"
license_length = Str.split(license, "\n") |> List.len
Stdout.line!("First line of ${readme_path}: ${first_readme_line}")?
Stdout.line!("Line count for ${license_path}: ${Num.to_str(license_length)}")
Lots has changed, even if it works the same under the hood! Let's list the changes:
- Functions get called with
(
and)
now instead of whitespace (also tags likeOk(val)
instead ofOk val
) - Function arguments are now surrounded with
|
pipes, just like Rust or Ruby - All variable and function names are in
snake_case
instead ofcamelCase
, which makes individual words in variables easier to read - Functions that might have side effects (like writing to a file) must have a
!
at the end of their name, which means!
is no longer an operator but just a suffix - String interpolation now uses
${
and}
instead of$(
and)
- We now use
and
andor
for boolean operators instead of the old&&
and||
operators to make them distinct from the new|args|
function syntax
In addition to the stylistic changes, there are some additional syntax features for error handling:
?
right after an expression that returns aResult
will either early return theErr
or unwrap theOk
value, just like Rust- If you put a space between the expression and
?
, it will use the function after the?
to map theErr
value first before the early return happens- This is really useful for giving additional useful for giving context
??
unwraps aResult
with a default value just likeResult.with_default()
, but with the benefit of only calculating the provided default expression if necessary
Most of the work to change existing Roc code to the new format can be done for you by the Roc compiler; just run
$ roc format --migrate
and the above stylistic changes will get converted for you. The main thing you'll have to do is replace any usage of Task
with an effectful function, AKA one with a !
at the end of its name. Task
has now been completely removed from Roc, which we think is a great improvement to the simplicity and readability of Roc. Also, Result.map
has been renamed to Result.map_ok
for better compatability with future plans for Roc.
This has been a whirlwind of changes! Don't worry, our hope has been to do the majority of the changes needed for Roc to look how it will in the long-term, so you won't have to do much migration after this feature push.
Some other APIs we've changed/added:
- Renamed
Result.map
withResult.map_ok
- Introduce some new
Str
operations:Str.with_ascii_lowercased
: make ASCII characters in a string lowercase and leave everything else the sameStr.with_ascii_uppercased
: make ASCII characters in a string uppercase and leave everything else the sameStr.caseless_ascii_equals
: compare the contents of two strings, ignoring case for ASCII charactersStr.from_utf8
: convert aList U16
to a string, failing on invalid codepoints- We already had this, but it changed error types:
- Old:
from_utf8 : List U8 -> Result Str [BadUtf8 Utf8ByteProblem U64]
- New:
from_utf8 : List U8 -> Result Str [BadUtf8 { problem : Utf8Problem, index : U64 }]
Str.from_utf8_lossy
: convert aList U8
to a string, replacing invalid codepoints with the "�" characterStr.from_utf16
: convert aList U16
to a string, failing on invalid codepointsStr.from_utf16_lossy
: convert aList U16
to a string, replacing invalid codepoints with the "�" characterStr.from_utf32
: convert aList U16
to a string, failing on invalid codepointsStr.from_utf32_lossy
: convert aList U32
to a string, replacing invalid codepoints with the "�" character
- Added some effectful
List
walking functions:for_each!
: Run an effectful operation on every element in a listfor_each_try!
: Run an effectful operation on every element in a list, returning early on anErr
walk!
: Effectfully walk through the elements of a list, building up state as you gowalk_try!
: Effectfully walk through the elements of a list, building up state as you go, returning early on anErr
That's it for now! Let us know if you run into any issues in the Zulip chat, we're here to help!
0.0.0-alpha1
We're starting with a new release approach, these files will stay available permanently in contrast to the latest nightly.
We now recommend most users to stick to 0.0.0-alpha releases instead of nightly-latest.
This current release is based on commit a089cf2 from the 6th of January 2025. These files are identical to nightly-latest published on the 7th of January 2025.
Nightly build
🕑 These releases are updated regularly, don't mind the Oct 22, 2021 timestamp. Ask Anton on zulip chat if you need older nightly releases.
macOS
You may encounter "roc" can't be opened because Apple cannot check it...
, you can fix this by executing xattr -d com.apple.quarantine roc_nightly-macosREST OF FILENAME
in the terminal. Or by downloading the file with curl to start: curl -OL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_apple_silicon-latest.tar.gz
NixOS
The roc binary in linux_x86_64 is dynamically linked so you won't be able to use it on NixOS. Alternatively, we recommend you execute nix-build https://github.com/roc-lang/roc/archive/a089cf2.tar.gz
, you can then use roc like this ./result/bin/roc repl
. If you want to build the language server, execute: nix-build https://github.com/roc-lang/roc/archive/a089cf2.tar.gz -A packages.x86_64-linux.lang-server
👇 Expand "Assets"