Hacker News new | past | comments | ask | show | jobs | submit login
Roc – A fast, friendly, functional language (roc-lang.org)
304 points by dlib 11 days ago | hide | past | favorite | 172 comments

For those out of the loop, Roc was spearheaded by Richard Feldman, who made major contributions to Elm.

Feldman is such a charming guy! I highly recommend checking out his podcast Software Unscripted and watching his many talks on YouTube.

The recent SU episode with Brian Carroll talking about WASM in Roc was a great listen.

Roc also has an active community on zulip, so consider stopping by :)

[1] https://twitter.com/sw_unscripted

[2] https://www.youtube.com/results?search_query=richard+feldman

[3] https://www.roc-lang.org/community

What happened to Elm by the way?

Elm is still delightful to use!

[1] https://taylor.town/elm-2023

Evan also announced some stuff about Elm and Postgres at Strange Loop earlier this year, so I expect another wave of movement soon

The talk is at https://m.youtube.com/watch?v=XZ3w_jec1v8

I also recommend watching it, though the conclusion I came away with is that Evan is kind of in a "next steps" crisis.

if nothing else it popularised TEA ("the elm architecture"), which a lot of other frontend frameworks have picked up on.

I'm super keen to see how Roc pans out, because it sits at an (IMO) riveting spot in the space of PL design tradeoffs:

1. The typesystem will be sound, ML-like, and so simple that any code that doesn't interact with external data will not need _any_ type annotations.

2. An aim to make it the fastest managed compiled lang around (faster than golang).

3. Functional.

4. A focus on fast compile times from the beginning (like golang).

5. Serde from rust is essentially a language builtin.

6. Zero side effects, only managed effects (which I think will do wonders for testability and mocking in a compiled language).

What I'm unclear about is:

1. Whether they'll support macros,

2. Whether their decision to build a whole new IDE will take away from the work that will go into an LSP (it will take a lot to pry away neovim from my hands).

It'd be dope if anyone more familiar can comment on the above!

Also, as feedback to Richard Feldman, your podcast is (imo) great marketing for your lang! It's what's made me excited about your PL.

EDIT: Forgot another feature I'm allured by: ability to run programs with type errors (as best as one can).

Glad you've been enjoying Software Unscripted, thank you for the kind words!

> 1. Whether they'll support macros,

The plan is not to support macros. A major reason is that macros tend to conflict with editor tooling, and I definitely have big plans for Roc's editor tooling!

> 2. Whether their decision to build a whole new IDE will take away from the work that will go into an LSP (it will take a lot to pry away neovim from my hands).

The IDE project has been deprioritized a lot (e.g. I don't expect any work to be done on it in 2024) because we realized there's a way to build the editor plugin ecosystem we want to build in a way that works across multiple editors.

There already is a preliminary language server, and there are instructions in the VS Code extension for how to get it set up [0]. I assume something similar should work for neovim!

EDIT: I just noticed that while I was typing this, the author of the Roc language server responded too...hi, Ayaz! Thanks for all your excellent contributions to Roc!


> The plan is not to support macros. A major reason is that macros tend to conflict with editor tooling, and I definitely have big plans for Roc's editor tooling!

I disagree! I've been working on a macro-heavy Rust project with both proc and declarative macros and the tooling makes them better. I'll add that there is immense value in turning repetitive code into "spreadsheet" style tables of data as well as being able to combine const expressions to get user controllable compile-time errors.

A common example of a tooling problem I've run into with Rust macros is that if I use a string interpolation macro (e.g. in an argument to println!, format!, or dbg!) a lot of VS Code tooling that works outside of macros stops working.

For example, I can't use normal context menu things on an interpolated variable name, like Go To Definition or Refactor. Similarly, if I do a semantic rename of a variable used in interpolation, it doesn't get renamed. Things like this.

Maybe these are solvable problems, but we're talking about widely used macros that have been in the standard library for many years, and even those don't have basic support for normal operations that Just Work in a non-macro context, in one of the most popular Rust editors!

> if I use a string interpolation macro (e.g. in an argument to println!, format!, or dbg!) a lot of VS Code tooling that works outside of macros stops working

I imagine this isn't that hard of a problem to solve (though maybe relying on VSCode to handle renames is part of the issue), but low-enough on the annoyance scale that nobody cares enough to implement it. I'm not going to argue there aren't annoyances with macros and that they're harder for tooling to deal with, but I don't think that's a sufficient justification to not have them at all IMO.

> The plan is not to support macros.

Gotcha. In every lang I've used a lot, I've found meta-programming (compile-time or dynamic) to be valuable (and often indespensible). I can imagine that a lang like Elm that is domain-specific can do fine without the expressive power of macros, but I struggle to imagine that for a general-purpose lang like Roc.

I'm sure you've ruminated on this, so I'm excited to see how it all pans out.

Maybe a Software Unscripted episode with someone who's written a lot of macros is in order? :) David Tolnay (serde maintainer) would be great!

> The plan is not to support macros

How do you plan on supporting meta-programming, then? Code-generation as a first class citizen a la .NET?

+1 for Software Unscripted! I know barely anything about compilers, but I really enjoy being a fly on the wall of these conversations :)

> 1. The typesystem will be sound, ML-like, and so simple that any code that doesn't interact with external data will not need _any_ type annotations.

I've tried using languages with this promise, such as Haskell, and also spent a lot of time with TypeScript, which makes a different set of tradeoffs, and I feel like I've spent enough time on both to know this is the wrong tradeoff to make. It sounds flashy to be able to say that no type annotations are necessary, but in practice what it ends up meaning is that you end up tracking down errors in the wrong parts of your code because the compiler can't figure out how to reconcile problems.

e.g., you have function A incorrectly call function B. How does the compiler know if A has the wrong arguments, or B has the wrong signature? It can't! I know that's a toy example, but it really does lead to a lot of real-world frustration. Sometimes the type errors are very far away from where the actual issues are, and it can lead to a lot of frustration and wasted time.

The TS approach of "please at least annotate all your function signatures" isn't nearly as flashy, but it strikes a much better utilitarian balance.

Oh I totally agree that it's a good idea to annotate top-level functions even if you don't have to, and better compiler error messages is one of the benefits of doing that. Personally I basically always choose to annotate them except in the very specific situation of writing beginner introductory materials, when it's not a given that the reader actually knows how to read the annotations yet.

One of the practical benefits of having full inference is that these signatures can be inferred and then correctly generated by an editor. Like I can write the implementation of my function, and then tell my editor to generate a type annotation, and it can always generate a correct annotation.

That saves me time whenever I'm writing the implementation first (I often write the annotation first, but not always), even if I end up wanting to massage the generated annotation stylistically. And unlike having Copilot generate an annotation, the type inference system knows the actual correct type and doesn't hallucinate.

To me, the main benefits of type inference at the top level are that they offer beginners a more gradual introduction to the type system, and that they offer experts a way to save time through tooling.

> Personally I basically always choose to annotate them except in the very specific situation of writing beginner introductory materials, when it's not a given that the reader actually knows how to read the annotations yet.

Having just gone through your tutorial (albeit not yet with a computer in hand, that's the next step), might I suggest putting those annotations in anyway? I suspect most of the people reading the tutorial will already be programmers, and one of the most useful things I've found when reading tutorials and guides is when the code examples look as much like real code as possible. When I'm reading that initial documentation, I'm not just trying to figure out what's different about this language from other languages, but I also want a sense of what it looks like to actually read and write idiomatic code in that language - what sort of formatting conventions are there, what do variable or type names typically look like, are there any common idioms, etc. Ultimately, my goal is to get up to speed and begin writing productive code as quickly as possible, so seeing type annotations everywhere is a sign to me that type annotations are good practice and something to get used to.

In general, I found the tutorial a bit too aimed towards someone learning their first programming language, which is a demographic that I suspect are unlikely to be using Roc any time soon! Even if they are a demographic you're targeting, I wonder if they'd be better served by a separate explicit "Roc as a first programming language" document that goes through the basics. Then in the main document, do some repl stuff at the beginning, but move quickly on to what regular development work might look like - starting a new project, writing functions with types, using tasks/effects, adding tests, dependencies, etc.

With all that criticism out of the way (sorry!) I do want to say that I love pretty much everything that I've seen so far, especially the focus on practical usage. It's great to see an example CLI and an example web server right on the home page - I feel like these are often left as complete afterthoughts for these sorts of languages, but they're the sort of real-world programs that dominate software in the industry.

I'm also really excited to have a play around with the effects/tasks system. It looks really powerful, but not too complicated to actually use as a base abstraction.

And I agree that having powerful type interface can be a great tool, even if you supplement it with type annotations for the sake of explicitness. Is there an explicit type hole mechanism as well, for getting the compiler to spit out the types it expects?

Thanks for the kind words, and thanks for the feedback!

> Is there an explicit type hole mechanism as well, for getting the compiler to spit out the types it expects?

Not currently, although you can write `_` for any part of a type annotation that you don't want to bother annotating (which means that part of the type will be inferred as if you hadn't written any annotation for it), and we either have or want to have "hover to see the type" in editor extensions.

The Haskell approach is "annotate all top level declarations" (even if not exported) and OCaml has module signatures. But both (and Roc) don't make up new "types" like Typescript does.

I think a general 'explicit > implicit' priority is good enough to cover most cases - a written signature takes precedence over an inferred one. The compiler can also simply emit errors at both sites and let the writer figure it out.

I usually think of writing explicit type annotations as 'pinning' the type in situations where things are inferred/generic by default.

> The TS approach of "please at least annotate all your function signatures"

The whole signature or just the parameters? I thought typescript is pretty chill about inferring the return type on its own.

It usually is as long as you don't do anything recursive (and a few select polymorphic instances), I can see people getting bitten by it.

Having written inferring compilers and used C++ extensively I appreciate the workings, but I can also see people getting stuck with it.

Rust takes the "at least annotate all your function signatures" approach as well. It's essential for making borrow-checking tractable (for both the compiler and the programmer).

Rust has the "you must annotate your functions signatures, because there is no global type inference possible" approach.

It's a carefully chosen, deliberate design decision [1]. Interface boundaries should be stable.

[1] https://steveklabnik.com/writing/rusts-golden-rule

It's unlikely that macros will be supported. Regarding editors, it's unlikely that effort on the advertised Roc editor will start in earnest some time soon. I actually recently merged an LSP implementation into the mainline compiler ([details on how to integrate here](https://roc.zulipchat.com/#narrow/stream/304902-show-and-tel...)), and that's likely to develop more in the near future, before a standalone Roc editor is available.

An aim to make it the fastest managed compiled lang around (faster than golang).

I find this an interesting perspective: That Golang is a compiled managed language. This is certainly correct. I don't see this being expressed to often, however.

Seems to be a language equivalent to a subset of strict Haskell.

There doesn't seem to be any particularly compelling reason to use it, and note that, unless they can use libraries from an existing language, there needs to be a really MAJOR reason to use a new language to compensate the lack of libraries.

Neat, looks like the website got an overhaul.

I like Roc's approach of detecting errors statically but still trying to let you run the code. If a snippet is work in progress and has an unused variable, Go or Zig will refuse to compile it. Yes, an unused variable indicates a problem, which is why it's not going to pass any sensible CI setup and make its way into production, but that doesn't mean I should be disallowed from checking whether what I've got so far works. Roc allows¹ running a program with type errors as long as you don't execute a code path affected by them, which I imagine is very useful for refactoring.

The platform approach is also interesting, but I don't know how it will play into code reuse. I guess the different io/platform interfaces might not be quite as big of a problem in a pure functional language? I'm not experienced enough to tell.

¹: I haven't checked how successful it is, given it's immaturity I expect there to be issues

Many java editors (notably, eclipse) work the same way, _if_ you configure them to do so_: Just run it, don't worry about the compilation errors. If the code never hits that segment (in java, if there's a syntactical error in source code, that entire class cannot be used, but if it's a semantic error (e.g. a reference to a function that doesn't exist, which is syntactically perfectly valid, that's a semantic error), only that method is 'tainted'. If you hit a tainted area the debugger kicks in, freezes the process, and breakpoints on the spot. You can then fix it if you want and continue, or inspect the stack and state of e.g. local vars and learn something.

What I find surprising is how few programmers I talk to are aware of this, let alone use it. I find it a significant productivity boost.

Extrapolating away from debuggers: Everything should be warning, nothing should be an error. Then adopt a policy that you don't check in warnings. I find it utterly insane that 'unused variable' is treated as an _error_ (in the sense that it prevents compilation). It.. just isn't.

I hear _lots_ of noise in the line of 'well but my dev team will just ignore that rule', but that's a "doctor it hurts when I press here" issue. You don't solve that by just being more beliggerent, you fix that by having a chat with the team.

I wonder what 'friendly' means in the context of 'a programming language', but if its: "Assuming you are not a complete idiot", that's a plus, I guess.

>If you hit a tainted area the debugger kicks in, freezes the process, and breakpoints on the spot. You can then fix it if you want and continue, or inspect the stack and state of e.g. local vars and learn something.

>What I find surprising is how few programmers I talk to are aware of this, let alone use it. I find it a significant productivity boost.

Forward to the past, as often is the case.



and its parent and child comment.

Haskell reports compilation errors as warnings too.

No real thoughts on the language yet, other than looks interesting and modern.

But, that website has one of the smoothest on boarding experience I've ever seen for a new language. From the inline REPL (with built in tutorial), to the code definition section, its insanely practical. Every new (& old) language should have a website and onboarding experience like this one.

No kidding. It went from the most barebones "Under Construction, check back later" website possible to one of the best proglang homepages I've ever seen.

I really like that 'fast', 'friendly' and 'functional' all link directly to long, substantive explanations of the goals and decisions related to those qualities.

For in-browser tutorials, Haskell does it on the main page, too:


For web UI, I always thought QisKit set the bar pretty high. It's intuitive and informative:


Svelte does a pretty good job too.


One thing I had to hunt for was what the backslash means in the first examples. Especially as it seems to be used for both string interpolation and function definition.

But other than that great to have a quite good idea of the language in just a few seconds.

It's both string interpolation and (anonymous) function definition.

    # Function Definition:
    addAndStringify = \num1, num2 ->
        Num.toStr (num1 + num2)

    # String Interpolation:
    "\(greeting) there, \(audience)!"
    # desugars to
    Str.concat greeting (Str.concat " there, " (Str.concat audience "!"))

Yes indeed! I love this web page. Sleek and very upfront with everything. Great job team!! Would love to help in any way.

Big fan of Richard Feldman's talks and Roc is one of my most anticipated upcoming language besides Gleam. Great to see that there's now a nice Roc website. Looking forward to how the language evolves!

I know Koka is more of a research project than anything else, but I think it’s by far the most interesting. Moving to effect handlers, the Perseus ARC algorithm, and identifying “functional-but-in-place” algorithms all feel like game changers.

Yes, Koka is evidently a inspiration for Roc, which uses Perceus, in-place mutation and their effect system is called "abilities". Roc aims to be something like the "practical version" of Koka('s ideas).

Oh I completely forgot about Koka, I remember looking at it a couple years ago. I'll have to give it a go again. :)

We have a very similar taste in PLs :)

If you are interested, «why yet another programming language?».

The unique selling point of Roc is clever optimization to convert purely functional source code to deep-imperative fast machine code, while keeping all the correctness of functional algorithms.

See this video of Richard Feldman for details — «Outperforming Imperative with Pure Functional Languages»: https://www.youtube.com/watch?v=vzfy4EKwG_Y

Among those clever optimizations:

- static reference counting (no GC, like in Rust, but with no borrowing and borrow problems);

- stack allocation of the data with no external links;

- hidden («opportunistic») mutability even in the cases, where Haskell or Lisp will copy the value.


> convert purely functional source code to deep-imperative fast machine code, while keeping all the correctness of functional algorithms.

All functional language compilers, interpreters, and/or runtimes ultimately have to do this by definition. The efficiency of transpilation varies widely.

Definition of resulting code as _deeply_ imperative was crucial in my phrase.

The only «sine qua non» optimization through opportunistic mutablity is AFAIK tail call optimization. But it is probably too well-known to call it «clever optimization» in 2023.

But, for example, applying a function to a list will produce the code allocating new list in, say, OCaml and Haskell, at least by default. And Roc will produce the code for mutating the list in-place _from the source code with the same semantic_ (see example for the Quicksort algorithm in the video above).

Compile-time lifetime analysis (that probably is not needed at all in functional languages with GC) and widely used unboxed values are way not common in functional language implementations. For example, in OCaml those features are still experimental (and probably never will be used by default, as in Roc).

I’d say that’s one of a few unique selling points. Some others I noticed:

- side effects are strictly relegated to async effects, eg all I/O calls return a future

- declarative static loading as imports

> - static reference counting (no GC, like in Rust, but with no borrowing and borrow problems);

Does this mean that it's somewhat equivalent to Rust with everything behind a `Rc` or `Arc`?

Rc and Arc traits are implementations of the _runtime_ reference counters. Runtime reference counting is sometimes less efficient than tracing GC.

But Roc counts references in _compile_ time. So it's like _usual_ (not wrapped in Rc<>) values in Rust. But in Rust the value is deleted from the heap when the stack frame with the _only_ link to it («the owner») is deleted. And in Roc the value is deleted from the heap, when the _last_ link to it leaves the stack.

So we have the machine code _almost_ as efficient as a Rust-produced machine code, but the source code with a much simpler semantics.

Do you have a written source for this? What you're describing is nice, but I can see so many basic cases in which it doesn't work, at least not without a borrow analysis much more sophisticated than Rust's, that I imagine I'm missing something.

Example: A linked list.

Nitpick: Rc and Arc are not traits.

Two main papers about this topic AFAIK are: «Counting Immutable Beans» by Sebastian Ullrich and Leonardo de Moura (https://arxiv.org/pdf/1908.05647.pdf) and «Perceus: Garbage Free Reference Counting with Reuse» by Alex Reinking, Ningning Xie,Leonardo de Moura, Daan Leijen (https://dl.acm.org/doi/pdf/10.1145/3453483.3454032).

See also Anton Felix Lorenzen's master thesis: https://antonlorenzen.de/master_thesis_perceus_borrowing.pdf

Mr. Feldman also mentioned some «alias analysis» library «Morphic Solver» from Berkley University, but I cannot find anything about it.

BTW compile time reference counting was already discussed on HN, for example here: https://news.ycombinator.com/item?id=19567666

> Example: A linked list.

IIUC recursive data structures like linked list and trees are not the problem for the static reference counting. Mutation (and, therefore, link cycles) _is_ a problem, but Roc is a clean language with no explicit mutation. =)

> I can see so many basic cases in which it doesn't work

Sometimes runtime reference counting is still used. But, of course, in way more complex situations than just processing a linked list.

> Nitpick: Rc and Arc are not traits.

Of course, my fault. I haven't written on Rust for a long time (and never used this language in a serious project).

edit: link added


I found what is «Morphic», mentioned by Richard Feldman.

It's an another experimental programming language with the static reference counting. «Morphic uses a borrow-based reference counting scheme which is able to eliminate almost all reference count increments and decrements for a large class of programs»ⓒMorphic developer team.

Site: https://morphic-lang.org/

Paper: https://dl.acm.org/doi/10.1145/3591260

Thanks, it makes sense now!

I think I've read a post by Niko Matskakis (Rust lead) who suggested doing something similar. That would be exciting to see!

That sounds a lot like Koka. Is there any relationship?

Looks interesting. I'm a huge fan of F# and think anything working in that hybridish space is the way to go. I'll have to dedicate some more time to this when I get a moment.

I've been on the F# website for 5 minutes now looking through damn near every page and I cannot find a single page that shows me a simple example program or the syntax at all.

Everything is hidden behind some kind of "let's get started!" wizard. https://dotnet.microsoft.com/en-us/learn/languages/fsharp-he...

Here's a non-wizard tutorial that I bookmarked when I started with F# (I also had a hard time finding a simple example at first):


What I like about this page is that it shows a basic project structure.

this website is great - should truthfully be 50% of the index.html of every language project ever.

Oh yeah. A key hindrance of F# is that MS treats it like a side project even though it's probably their secret weapon, and a lot of the adopters are dotnet coders who already know the basics so the on-boarding is less than ideal.

https://fsharp.org/ is the best place to actually start, although i'm guessing you did and went to the hello world which leads back to ms's nightmares.

https://fsharpforfunandprofit.com/ is the standard recommendation from there but there's finally some good youtube and other content out there.

They have a browser repl as well https://try.fsharp.org/

agreed, a "learn dotnet via f#" approach for people with experience in other ML languages would be excellent.

fsharp.org is actually the offender. lots of links to basically nothing and quite a few of them are a dead end 404.

> hybridish space

I'm sorry, but what do you mean by that? Roc is "as" pure as Haskell (or Koka), if that's your point.

I glanced at the example code and it looked like it allowed side effects, but maybe I was wrong. I haven't had much time to mess with it and seemed to be able to hard crash the repl doing some testing so it's something i'll have to look at later.

Well, yes, if there are no type annotations because all types are inferred, you don't see the effect "types".


Then to my limited understanding that's less "pure" than haskell isn't it, which doesn't allow side effects and thus forces monads?

Roc doesn't allow side effects. All effects are wrapped and returned from a function. So this is just as pure as haskell. Though it may not be exposed in the same way as haskell, effects still boil down to something akin to monads and callbacks.

Honestly it looks like basically the same as getline/putStrLen from the tutorial(1) in the link below, just not written in an intentionally obtuse language.

Considering how much more approachable this Roc documentation/naming is, I'm wondering if it isn't so that the people writing Wikipedia's math pages are probably the same people that are drawn to and writes Haskell/monad "tutorials".

1: http://learnyouahaskell.com/input-and-output

I was thinking of this the other day. I was trying to remember the name of the language and to look it up.

Elm really broke my heart, I believed it will go places it never went. Roc honestly, I am OK to play around with it and build whatever makes me happy.

Having a play with Gleam right now. Roc's managed effects sounds interesting, maybe Gleam could layer something similar atop Erlang's OTP? Right now, outside a database, it's not clear to this newbie how state is meant to be managed in Misty, the Gleam web framework I am kicking the tyres of. If I can be bothered, I was seeing myself having to delegate state management to a separate process (which Gleam seems to support well, but it's work I didn't anticipate and I am at this stage only playing).

Edit: related to state management, the "platform" concept looks interesting too https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#...

I imagine state should be managed via GenServers[1][2], since that's the general BEAM way of doing that.

1. https://www.erlang.org/doc/man/gen_server.html 2. https://hexdocs.pm/elixir/1.12/GenServer.html

I don't know, after having used Elm and seeing the community accused of "hostile attacks" by one of the main contributors (who is the creator of Roc now) [0], I don't feel that it's worth my time to put into learning it, even if it is objectively good; I simply cannot know what the creators will do (or refuse to do, in the case of Elm) in the future, especially in a BDFL governance paradigm. This was in fact why I stopped using Elm after a while, it didn't seem like they wanted to ever address the issues they had, or even to acknowledge them as issues in the first place.

I know in my linked [0] that Feldman has since apologized, if only because the comment was being linked to so often [1], but again, why not use any other language where the creators are not so hostile, some even going so far as to say that they "wouldn't trust anything that Richard Feldman was involved in. He was instrumental in making the Elm community a hostile and unwelcoming place."?

[0] https://github.com/gdotdesign/elm-github-install/issues/62#i... (check the edit history)

[1] https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...

Wow, this is depressing to read. :(

5 years ago I was upset and posted a comment that was unfairly harsh to another commenter. I apologized at the time, and I meant it. I definitely should not have made the harsh comment that I did. It was wrong. There's no excuse for my having written it.

There are a lot of people working on Roc other than me. I'm not even the top committer anymore. [0] I hope you can find it in your heart to give their work some consideration, if not mine.

[0] https://github.com/roc-lang/roc/graphs/contributors

As a small datapoint, I brought up Roc at work last year and a colleague said “it looked interesting but it’s the guy from Elm isn’t it?” and brought up this.

As a manager, I empathize with the frustration you were feeling. Steering a team or a community towards a vision is very hard. Just when you think you’re getting somewhere, someone does the exact opposite and mixes people up. It’s easy to lose patience. I’ve made similar mistakes on popular projects and was fortunate enough that no one publicized them. I was allowed to learn from my mistakes without being punished for it.

I don’t have any advice on this. It’ll probably turn out fine.

Thanks for this comment. Personally, I appreciate how human and humble your response is, and Roc looks great.

Come join the open source software community. Everything you say will be used against you in the public court, forever.

I believe in second chances. From the GitHub link:

> EDIT 5 years later: You can see in the edit history of this comment what I originally wrote here; I was upset and said unkind things that I regret, and which nobody deserved to hear. I apologized at the time and I still feel I should apologize again, unequivocally. I was in the wrong here.

Yep, this is good enough for me, and I suspect for anyone who is not hellbent on holding a grudge.

Seriously ppl, go use a language where the creator is a paradigm of humanity. Maybe Python is a good choice?

Seriously, tho, that's the comment that "made the Elm community a hostile and unwelcoming place" and is still being dredged up after 5 years? That comment can barely even be considered harsh, and is nowhere near hostile.

Is it really worth tearing down someone's life, monitoring the internet for any time their name appears, just so you can spread the continue to spread the hate toward him after so long? This is where you make your stand?

A paragon of humanity?

I don't see what was so harsh? I checked the edit history, I saw the original comments and subsequent minor tweaks. His response was rather testy and stubborn (as is the case with the Elm team generally, it seems), but not as much of a dick comment as I have seen elsewhere in GitHub issues.

There is some more context here: https://lukeplant.me.uk/blog/posts/why-im-leaving-elm/#forka...

> Threatening a person with exclusion from a community for attempting to patch the source code is quite antithetical to the spirit of Open Source, as far as I can see.

From this post it feels like they never even understood the original comment about going against the project’s goals. The drama created around this is much, much larger than the issue warranted. If Roc keeps this audience away, maybe that is good thing.

Note that they were never prevented from forking the project (how would you even do that), instead they chose to try and stronghand the project into accepting their view, which is also not healthy for OSS. Maybe their Elm fork would be mainstream by now if it really catered to developers’ needs.

There's a certain infini-grudge-holding, emotional, drama-stirring archetype of software developer that's best left out of the community, especially that of a new, fledgling one.

It's always the same story, too. Someone felt personally wronged by something actually quite minor like their their PR getting ignored/rejected with perhaps a tone too snappy for them, and now they have a personal vendetta until the end of time with no rock nor HN comment section left unturned from them lingering in the past.

Sometimes you need to leave the theater and let the rest of us enjoy the show.

Hopefully a mod sinks this entire thread so we can read interesting thoughts about Roc.

There's no evidence thus far in the Roc community thats it's anything like ELM's community.

Seems like the Author of Roc is cool now, that was 5 years ago and hasn't done the thing you fear he might do? people get testy, say things they regret.

I understand trust is earned, but it's been 5 years. and the Roc community thus far have been really nice, welcoming and collaborative. I get Elixir and Ruby community vibes from these contributors.

Pick your battles I guess?

Sure, but there are also a lot of languages to learn, in a vacuum I might learn Roc but now there are other options that don't have such history, it is not near the top of the list.

> other options that don't have such history

Roc isn't Elm. RF is one person in that community, and he said something he regretted 5 years ago and has since not repeated that mistake.

Do you know the moral dealings of every developer of every piece of technology you use?

When it comes to Roc and It's community..ask yourself.

    “Am I sure that what I am going to say is true?” 
    “Is what I'm going to say a good thing?”, 
    and “Do I really need to say it and is it useful?”
Is that comment from 5 years ago really the most important thing about the Roc Programming language, that anyone reading the comments need to know? Is RF the reason you walked away from Elm?

It's not about moral dealings, it's about whether I can trust the creators to not mess up a second time if they had already messed up once. We were shipping Elm in production and we moved away because any issues that were brought up that we wanted to see solved were swept away. Eventually it wasn't worth keeping the Elm codebase around. So, why should I trust one of the same people again? We already learned an expensive lesson one time around.

> When it comes to Roc and It's community..ask yourself.

Sorry, but this kind of faux niceness is precisely what stopped people from asking about issues, as it was always argued that asking about such issues was not "useful," after some time. So yes, I do feel the need to bring up this topic if only for others to evaluate the creators themselves rather than only have "good" things to say that "really need" to be said.

So RF being questionably rude in a PR comment caused you company to drop apiece of technology?

One cut among many. Another was the insistence of Evan to cut out escape hatches and insist that everything be done solely through Elm. It is not just one person, the entire community was part of the problem, in one way or another. I don't think about Elm much anymore but what I do think of it does not inspire confidence at its creators' future endeavors. Of course, if people want to use it, by all means, but being burned once, not just technologically but also financially, I would not want to be burned once more.

I appreciate the context because it sheds further light on a big problem with Elm the project, but that context doesn't change what he said, which simply wasn't that harsh or mean. Like, from your original comment, I expected some kind of personal attack on the other person lol

I believe people should be given second chances. There’s a good chance that the Elm debacle has taught most people involved a thing or two.

No doubt everything could've been learned and heeded by now, I think it's really, really, really hard to say "OK, so then everyone should go and try to raise $4000/mo for the new project they have." Even just using a programming language is an investment of time and trust, too, lest you want to wind up stranded on some-old-version-of-Elm island with tens of thousands of lines of code.

Elm also seemed very promising in the beginning, and honestly I don't even think that comment is so abhorrent on its own. I think Elm died the death of a thousand cuts. If it had only been one errant comment somewhere, it would've been mostly forgotten about by now. Instead, it's Elm that's mostly forgotten about.

So I say best of luck, but also... No thanks for now.

edit: Just so it's completely clear, I am actually implying that "maintainers being dicks" was actually not the problem with Elm. I think people just got especially infuriated by it because they were sick of trying to deal with Elm's breaking changes, of which this represented one. I remember going through and learning Elm and like literally months later everything was completely different and I no longer knew how to make a basic hello world application (around 0.16 or 0.17 maybe? Can't recall. I just remember that effects had changed a fair bit.) I know that to some degree this is the nature of a 0.x product, but at some point it's like "OK... then who is supposed to even use this?" Among other issues of course.

This is how I feel too. Sure, it was 5 years ago and things might have changed, but there are a ton of other technologies and languages to learn, so why not learn something without all of that previous drama? These things indeed might take a significant time inventment so I'll just focus on something I know might be more interesting or durable.

I would not even have known about this drama without the person who reminded us of it. That said, I still do not care about it at all.

Imagine me not using Linux because of Linus being harsh (yet educative) to some people... or not using OpenBSD because of Theo... or not using Common Lisp because of #lisp... :P I have received some hostile feedback personally, but they were in the right. I did not take it to heart but I learned from it.

That said, I have checked the edit history and I cannot see what the fuss is about. Welp. Moving on.

It's very easy to say this having not invested anything into Elm and not been there. I'm just thankful that most of what I invested in Elm was only time, and we never actually wound up deploying Elm to the frontend.

Forget about all of the drama, imagine if you used Linux and it stopped updating at 2.6. Elm has been at 0.19 since 2018, and that's not because there's nothing left to improve on.

> imagine if you used Linux and it stopped updating at 2.6. Elm has been at 0.19 since 2018, and that's not because there's nothing left to improve on.

Yup, that definitely would be an issue.

Wait till you find out about Linux

Maybe I'm not understanding something, but I would use a programming language I liked even if one of the main contributors was the worst human on earth.

I don't understand why people have to make technical stuff personal.

I think we need to be able to accept apologies when someone makes them... otherwise we are all doomed.

Everyone has their moments no? In person Richard seemed like a super nice guy and the many lectures he did for Elm really showed a passion for helping improve the day to day experience for developers. He was also super active on the forums and slack helping people out.

There is an argument that people who made mistakes and genuinely learned from them and apologized could be more trustworthy than people who had not made that mistake to begin with.

Does Roc have any features that a Haskell programmer could consider improvements?

I think it boils down to:

  - simplicity
  - strict evaluation model
  - devx
  - faster runtime
  - built in effect system
I love haskell and write it every day, but I have the feeling that the language is probably too complex to really cross over to the mainstream. I remain convinced that the advantages of a pure functional approach are so compelling that we will one day see roc or something like it be the default choice for most programming tasks, and am really excited to see so much progress being made on the language.

Not really, no. Like Elm, it strips away practically everything that wasn't already in 1970s-era ML. It's much closer to a trimmed-down Ocaml than it is to Haskell.

Some in the ML community think a simpler language has advantages over a more expressive one, in some cases.

For example: https://github.com/fsharp/fslang-suggestions/issues/243#issu...

Not just the ML community. Go's simplicity is often derided, but I think the best in class tooling (dev tooling like gopls, golangci-lint, deployment tooling like ServiceWeaver, Goreleasor, etc) and easy understandability more than make up for "what yuu can't do"

Not just in the Go community! Everyone believes in "as simple as possible". The disagreement is about "but no simpler".

Given its strict purity and use of typeclasses over modules I would say roc is more like haskell than it is ocaml.

Haskell programmers tend to love their monads, but the treatment of effects here ("Tasks"), looks to be - and this is highly subjective - more intuitive and straightforward.

ETA: Also if I'm reading this right Roc appears to natively support some kind of row polymorphism. That's a nice-to-have.

I think algebraic effects usually just compile down to monads under the hood? As I understand it, it’s more like a cleaner interface to model side effects, than some new approach compared to the tools that haskell gives you out of the box?

No, not necessarily (that's just how some(?) of them are implemented in Haskell, and that's slow too). Since 9.6.1 GHC has primitives for delimited continuations, with which effects should be implementable in a more straightforward and performant way.

Alexis King, who added these primitives to GHC, on (delimited) continuations https://www.youtube.com/watch?v=TE48LsgVlIU

I had understood that the delimited continuations stuff was more like performance optimisation for the (slow) free monadic effect systems than a fundamentally different theoretical foundation for modelling effects in a pure language?

fwiw we also have fast effect systems in Haskell these days that are more like fancy type sugar on top of the ReaderT over IO style of things (effectful seems to be the most popular).

I've thought that all "native" (in the compiler instead of a library) implementations use (more or less) delimited continuations (some kind of temporary stack moving/copying). OCaml : https://github.com/ocaml-multicore/ocaml-effects-tutorial#3-... And Koka: I haven't found the paper/docs right now.

I know about effectful, but that doesn't use Reader (but provides one) but more or less directly IO (Ref) and "evidence passing", that's why it is faster than the other ones, the drawback is not being able to use non-deterministic effects and noo such thing as coroutines. But I talked about eff ("native" delimited continuations) should be more or less the same, maybe a bit faster, than effectful, but enable non-determinism and coroutines.

First of all — way faster machine code.

Many other things are features or bugs depending of your preferences. For me, for example, eager evaluation is a big improvement, but YMMV.

> eager evaluation is a big improvement

Does it have any support for laziness? E.g. could one define the list of all fibonacci numbers similarly to Haskell's

    fib = let f a b = a : f b (a+b) in f 0 1

How does it compare to HVM [0]? It is an alternative to GHC that in some cases is orders of magnitudes faster, at least from their benchmarks.

[0] https://github.com/HigherOrderCO/hvm

Roc uses perceus, which is a reference counting model that allows for opportunistic in place mutation if it is safe to do so. HVM is more like a fundamentally new evaluation model that is parallel by default. They are both very exciting, but HVM is much more radical and probably needs at least a few more years until it starts to be seriously practical.

i thought the orders of magnitudes faster benchmarks were around lazy evaluation, and probably wouldn't apply here.


Convenience instead of historical baggage, maybe?

All languages have some amount of historical baggage, but I'm not sure what you're referring to here.

If anything, Haskell gets a lot of eyerolls for its slow moving pace and for trying to build a language from mathematical first principles.

It's not perfect (eg.: Monad was not designed to be a special case of Applicative in the beginning, I believe) but it's better at "avoiding baggage" than many other languages I know of.

Haskell is a wonderful language, but I don’t think you can claim it’s baggage free. It’s certainly accumulated it’s fair share of technical debt (more in the standard library than the core language to be fair). The endless proliferation of often complex and hard to understand extensions also certainly raises the bar for beginners.

> I don’t think you can claim it’s baggage free.

Did I?

The webpage is very nice, with 3-4 steps tutorial to engage people and an example with interactive explanations

Just don’t try to use it with Paper.

Lol. But it beats Scissors. :)

Looks interesting for sure and I like the syntax. Also, they seem to be using both Zig and Rust in their compiler from the looks of it?

Zig for the standard library, Rust for the compiler.

A video about the design decisions of the (hash) map: https://www.youtube.com/watch?v=Z3UGuaJWbaA

Refreshing to see a tech, and better yet, proglang post on the HN front page again, after the last few days.

Need less Altman, and more altlang posts.

I'm excited to take a look at this. I learned F# early on in my career and really enjoyed it. These days I'm into ultimate simplicity. I really like V-lang. It has the simplicity of Go but adds some ergonomics that Go has been missing. Also, it can seamlessly interact with C libraries. So, that is my current favorite language. Hopefully Roc will be my favorite functional language :-).

Lets make Tcl/Tk GUI bindings for this! Please it would kick python butt! Roc on!

Just the other day I was looking at this website and it was the old one. Does this mean that Roc is out of alpha/beta?

As a big elm fan who does backend work, I’ve been looking Roc for a while with a lot of excitement.

I think Roc has a lot of good ideas, especially the backpassing syntax sugar and that there's only one way to declare functions (anonymous or not). Excited to see where it goes!

Their FAQ is an eminently reasonable breakdown of their choices:


I don't fully agree with all of the reasoning, but it's a reasonable position to stake.

Yes, it was exceptionally well written and argued! Did you find any of the arguments faulty, or lacking counterweight? Or do you just weigh some drawbacks less harshly so you want some of the features they decided against?

I pretty much only really disagree about HKP. Not specifically because I want monads, but having used C# for 20 years now, I feel it every time I try to create reusable abstractions, and so much of the ecosystem would be simplified had HKP been available. I don't see any issue with not having a monad in the std lib and having a Roc sub-community create their own extension library.

I do suspect there's a way to solve the issues they raise with currying, but haven't thought about it enough to be sure.

The only other complaint I have that isn't addressed in the FAQ is the choice to use '\' to start a lambda. I've never liked that syntax anytime I've seen it. '->' as a infix operator is sufficient to disambiguate, so given all of the other good ergonomic choices they've made, that just kinda sticks in my craw.

I'm super excited to see Roc up on HN.

I like the 'be fast' and 'be haskell like' approach.

I see you have an Earthfile in the repo. Let me know if you have any Earthly feedback or if I can help with the build in any way, @rtfeldman.

( We've been working on making Earthly faster for Rust builds by using cache mounts. )

Has anyone else noticed that functional languages go heavy on the special keywords and operators? It feels like theres a larger cognitive load (more specific keywords to memorize) when learning languages like F# or OCaml compared to C or Python or Java

Clojure doesn't. I'd really, really love to see a fast, statically-typed, functional lisp.

Carp - https://github.com/carp-lang/Carp - "A statically typed lisp, without a GC, for real-time applications." where it's "Ownership tracking enables a functional programming style while still using mutation of cache-friendly data structures under the hood".

You might like Coalton, which is statically typed, functional language embedded within Common Lisp. However, it hasn't reached version 1.0 yet.


Actually they both (and OCaml has a whole lot of almost never used OOP - that's where the O comes from) have _way_ less "syntax" than Python or Java.

I just did some quick math. If you count all the keywords and operators for F# in microsoft's documentation, you come to 150 symbols. This doesn't include the nullary operators (of which there are 14)

Counting all the java operators and keywords, you get 84. This doesn't include assignment operators like "+=" or "-=" (11 such operators).

ChatGPT tells me that python has 36 keywords and 28 operators (not including the 13 assignment operators). This seems low and may be missing some syntactical sugar operators, but even then 64 is a far lower number than F#'s 150. Much debate could be had about which of these operators are fair to count or not, but it seems preliminarily that the data supports the position that functional programming languages (or at least F#) tend to go heavy on special keywords and operators

You're right, there actually are more. Interesting, I "feel" the opposite.

Haskell (55 + some more, because of the grouping): https://wiki.haskell.org/Keywords

F# https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...

OCaml: https://v2.ocaml.org/manual/lex.html#sss:keywords

Python: https://github.com/python/cpython/blob/3.12/Lib/keyword.py

Java (I think these are the current ones): https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_k...

A few of the Haskell ones are introduced by extensions, so they're not part of the language proper.

Yes, I know. Same for OCaml with PPXs. That was just to show that even Haskell has many, even though most operators aren't keywords but "normal" infix functions (of type classes).

> even though most operators aren't keywords but "normal" infix functions

yes, that is also important to mention

Can you clarify what you mean? I don't think Roc actually has that many keywords or operators in total. I would bet that C has more keywords that Roc.

I do agree that default convention may rely heavily on a few syntaxes that aren't as common in procedural or OO languages.

Still way better than doing C++, speaking as someone that likes C++ since the Turbo C++ for MS-DOS days,

Since the type is inferred, why can't the module name by convention be inferred from the data type in pipe operations?

So instead of:

["a", "b", "c"] |> List.append "d" |> List.append "e" |> List.append "f"

You could have:

["a", "b", "c"] |> append "d" |> append "e" |> append "f"

Since Roc knows that the type returned from each function is a List.

Roc cares a lot about explicitness, so I don't think this would be a wanted feature. That said, it is easy to get this functionality with something like ``` append = List.append ```

An important note is that any module could expose an append function that has the same interfaces as `List.append`, so that could easily lead to confusion.

Interesting divide-by-zero behavior when I use the interpreter in the webpage:

  » 1/0

  1000000000000000000 : Frac *

Oops, that's a bug - just opened an issue for it: https://github.com/roc-lang/roc/issues/6027

Thanks for pointing it out!

You won't like the result of `0/0` either ;)

Roc is definitely interesting and I like the platforms idea. The error messages are clear, but calling them friendly is clearly not something they've reached yet.

Just installing and trying to reach a valid hello world going just by the errors and it's actively rude within three error messages.

Also it's missing the final newline

> it's actively rude within three error messages.

Can you share those error messages? I am sure that is not the intent.

Looks cool but I am somewhat weary of languages that are so wholly dependent on whitespace for significance. I say this as a Python user... but my favorite part of Lisp is the homoiconicity. Things become very intuitive ... whereas the syntax of a language like this takes much longer to grok.

Why “\(var)” instead of one of the other, more prevalent string interpolation escapes?

Is it a Haskell/Elm thing I’m unfamiliar with?

Is Roc inspired from Elm? Can’t help but to notice a very strong resemblance between the two.

Roc looks great, props to everyone involved in designing this language!

Is there an (C) FFI planned?

Yes and No. Roc fundamentally is built on top of platforms. Platforms are communicated with through cffi. So cffi is fundamental to roc. At the same time, roc will never have general cffi where a package can wrap an arbitrary c library. Those primitives must always come through the platform.


camelCase instead of snake_case is such a turnoff :(

Even coming from Ruby, which uses snake_case, I've come to prefer camelCase over both snake_case or kebab-case. Since camelCase compacts more into a single token (separating it from what comes after), and it better passes the squint test.

Not a fan of the usage of backslashes \

0. I don't see type annotations.

1. Why another language and not a better runtime for an existing language with an install base that already exists?

0. Roc is capable of always inferring types. So type annotations are never required. That said, type annotations are used commonly and 100% supported.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact