I like the generalization of `Unit` type (type that has only one value) as empty product type (`{}`) and `Never` type (type that has no values) as empty sum type (`[]`). While it is quite common to represent unit type with empty tuple in many programming languages, it never occured to me that never type could be represented with empty union - but it totally makes sense.
This is exactly what rust has been doing since forever and what it encourages. Something like Infallible in the std is exactly defined as an empty enum so compiler knows it has no possible values
@@uwundrej because in Rust, you can't have nameless sum types, so you can't cleanly define an empty sum type that will play well with other empty sum types
@@aly-bocarcisse613 I consider this superior to do notation, because the bind is not baked in. - Yes, you have to provide it on each line, but also you can arbitrarily combine without worrying with ugly things like monad transformers.
The backpassing syntax, yes! I've always wanted that!! -- Exactly that feature. - Just "wrap the rest of the body in a closure" and nothing else. Scala almost has it in for loops, but still quirky. Monad do syntax forces using bind for no reason. All one wants is this rewriting. Putting the bind manually at the start of each line is fine, and importantly it lets me easily combine different monads, instead of the crazy mess in Haskell. - Much more general and useful than the "async/await" syntax everybody is incorporating stupidly. .... Yes, yes, it's slightly faster, and it works better with loops and mutable variables - hence disallowing multiple invokes of the continuation, etc.... I get it. But this is so nice and useful!
The backpassing for await is very similar to a very powerfull mechanism in F# which is called “computational expressions”. Which is also a some kind of syntactic sugar in F#.
so this language has tag unions, which are not to be confused with tagged unions. Except they also can be tagged unions, because the tags may have associated types. got it
For whatever reason this language is very appealing, there is a subtly in it. I will definitely be on the look out for it's progress, and will likely spend much time grasping the ins and outs.
I am almost certain there will eventually be a language server, but Roc is trying to do some really innovative things with the editor. We have a large focus on developer experience and are trying to push boundaries in ways that wouldn't fit into a language server. That is why we are building an integrated editor.
Richard talks about it here: ua-cam.com/video/cpQwtwVKAfU/v-deo.html His argument is that the ceiling for how much help a language-specific editor can give you is much higher compared to a plugin. Examples he brought were Visual Basic, SmallTalk, Pharo and Dark. Definitely a lot of reinventing the wheel on common editor features though, I hope it won't distract too much from the development of the language itself, pretty excited about it!
Very interesting language. I've been collecting design ideas for a potential future language and it's uncanny how many design decisions overlap with what is here.
the only problem with Result is, that it doesn't show where the problem happened. - While I love tail call optimizations and many things .... in large projects, I don't think I would be able to find errors in a reasonable timeframe without stacktraces... - Yes, I could wrap everything in very specific tags, but then I would still not know the call chain, and the bug is often 20 calls higher ... (as in: oh, the url was wrong, nice it was included in the Result, but why was it wrong? and that is still a simpler case to find) - This does not work well with any async system (unless it tracks it explicitly; or go-like green threads), and I dislike stacks ... but I wish there was a good solution to this... somehow building the stack-trace as part of args ... but that would be slow ... Anyway, language looks really nice!
@@beauteetmusculation8191 zig and rust are might be more like where your WASM "syscalls" where going to be implemented and where roc might be the stitcher, it also map nicely with how platform concept mapped to those WASM "syscalls".
Not even a fan of Function Style Programming and space indentation But this looks so good. So much thought was put into this. It all feels so cohesive and well designed. Kudos
I'm wondering how do you handle error unions that has clashing definition? Say I have two function f and g, f can throw an (ErrorX Int) while g can throw (ErrorX String), and (await f g) should result in compile error since Int and String is not dimcriminatable, in this case do I have to map one of them to use a different constructor?
There is no issue in roc making a function that returns (ErrorX a) where a can represent any type. So the wrapping function that calls g and passes it's result to f would first await on g, potentially returning (ErrorX Int). If it doesn't fail, it will give the unwrapped result to f and await on f. Then if f fails, it will return (ErrorX String). Finally if nothing failed, it would return the overall result.
2:05 SIDE EFFECT!! 😱 just kidding. Nat is a very useful type! Thanks! And very clever to register the "platform" as a plugin which the code uses! That is very good design imo. But some things seem strange to me: * why do you type annotate function parameters as if the function is an n-ary function? Isn't partial application a thing in Roc? If yes, I definitely prefer Elm's syntax which makes clear, that we always get back a unary fn! * why are Union types written as lists? Can you iterate them? * why does List.get first take the list and then the index in contrast to Elm? * why do you distinguish between constants and functions which take no arguments and always return the same thing like in Elm? Is it because the syntax is more streamlined this way when you declare anonymous functions (which you had to write like this \arg -> body in Elm)?
It makes sense to me. I would use the same, if I was making a language. Why use a different escape? \( already doesn't (shouldn't) mean anything, and () means clearly specifying bounds of an expression. It's the most sensible syntax. - The only reason to use something else is for direct identifiers like "asd $a asd" which is useful, but has caveats. \() forces using () always, but is nice otherwise.
I had the same confusion, guessing he left it out of the talk for time consideration. Their backend is haskell so I'm guessing they've heard of do notation lol. I'm not sure it's better than monads in an abstract sense, but maybe they feel it's a lot easier to understand than monad operators, classes and instances. Remember Elm is really opinionated, Roc is going to be following in that ethos where FP needs to be accessible to newcomers.
I consider this superior to do notation, because the bind is not baked in. - Yes, you have to provide it on each line (here called await for tasks), but also you can arbitrarily combine without worrying with ugly things like monad transformers.
It looks really cool, but two things bother me, why is the language not curried and why do you use so many abbreviations? I know that the abbreviations thing is very common in functional languages, but is it really so much faster to type "Str" and "Err" instead of "String" and "Error" in an IDE with autocompletion?
Must agree with you on the abbreviations... I could have been doing functional programming back in the 1980s if I hadn't been so turned off by LISP's annoying and meaningless abbreviations for everything.... I could have been doing functional programming in the early 2000s if I hadn't been so turned off by Haskel's annoying and meaningless symbols for everything............. ;) JavaScript is flawed in so many ways but, in JS, I can write functional code and then read it back like an articulate human being instead of a malfunctioning android reading SMS messages.
V is guilty of this as well, some other recent languages too... I don't know why this bad practice seems to have returned in recent years for some reason. It seems to signal somebody valuing "coding fast" above "readable code" - but as you said, IDE autocompletion, so even that doesn't make any sense. Perhaps some of these people code in text editors - since they're working on new languages that may not have any substantial IDE support yet, a combination of those two factors might be the explanation. It's misguided either way. 😕
Could not agree more, we use languages as an abstraction for not doing machine code directly, if you really need to save some bytes by writing Err instead of Error, then you probably need assembly more than a high level language. Let's keep it human and readable, even if this means this is a mouthful to read, explicit is better than implicit.
re: OP - it's not about autocompletion re: readable, thats wrong imo. re: haskell's symbols, i think those are awfult oo. re: coding fast... i honestly don't think it improves programming speed in any significant way at all. so it can't possibly be for them to type things faster. short names are more readable, especially in long lines made up of say, just four lines it's a lot easier to find Err than it is to find Error which is ~60% longer. granted, it's a bit contrived in this case but it's a lot more important in functions like getOr vs getOrDefault. even more important, after a certain point i feel like it's more a chore having to read the full method name... e.g. "concatenate" vs "concat". as long as it's _extremely_ clear what it refers to i really don't see how it's _not_ a good thing for readability. re: let's keep it human and readable, explicit is better than implicit... it _is_ explicit. but just because you speak english doesn't mean programming languages are also english.
I'm not sure, aside from compiling to wasm, what this language innovates on? All these features existed in Scala for example for absolute ages, especially the "I haven't seen it anywhere" Backpassing, which existed in Scala for years and is called for-comprehension. The syntax is just identical.
haskell is a research language that is a bit anti-beginner and has some pitfalls, like strings being linked lists. if I understand right, roc is trying to orient toward business use where performance is an asset.
How does one separate Tags from other types? Are there no other types? - I can imagine List being defined as List a : [ Nil, Cons a (List a) ] ... but then what is List.map ? Is the function somehow defined on the Union ?? - Are Tags namespaced? It seems like they are not, which would bite one in bigger codebases...
I’m guessing that the creation of this language signals that his experience at NoRedInk convinced him that Haskell is just “too much” for the average backend developer. Or maybe that Elm+Haskell was too great an impedance mismatch.
I don't think that is it. I think it is more so that Elm is a lot more fun for most people to develop in. It is simply a much nicer and more catered experience (of course more limited as well). With that in mind, many people have wanted Elm for systems level programming for a long while. I think this is more about the great Elm experience than Haskell being "too much" or "too complex" for must developers.
@@AdrianBoyko they seem to try to avoid keywords as much as possible. The `:` is already reserved anyway, and `UppercaseIdentifier : ExistingType` can't possibly be a signature, so _why not_ just define this to denote a type alias?
To me it seems that it is just syntactic sugar, for anonymous functions, and not bound to monads or applicatives, like do notation (And as someone else pointed out in another comment, do notation has an implicit >>= in Haskell). So from what I understand, backpassing could be used for any higher order function, which takes the function as the last argument.
It's a general-purpose syntax for continuation-passing style, which means it does need the monad bind operator (e.g. Task.await) explicitly writing on each line. An interesting idea indeed.
Haskell is also going in the direction of having a CPS engine builtin for faster effect management. It’s not interesting in terms of generalization, but generalization is most of the time not the interesting thing in language design.
An interesting language, and it has an ergonomic Elm-like syntax. May I ask, though, what the language's motivation is, when other similar languages, like Elm, Purescript, Haskell, Typescript, ReasonML, SML, Idris, and (maybe) Elixir, already exist?
I can't speak for Richard, but I think this programming language fills a niche that doesn't necessarily overlap with most of the languages you listed. Firstly, Elm, Purescript, Typescript, and ReasonML are very web frontend targeted. Though Roc can compile to web assembly and thus make a web frontend, that is not really the main focus or target. If you want to make a web app with a extremely nice pure functional language, Elm already has that space covered. I don't know SML or Idris, but to my understanding SML, Idris, and Haskell are the languages the overlap the most with Roc. I think one core difference between Roc and those languages is the same difference between Purescript and Elm. Purescript is extremely powerful, very academic, and quite daunting, while Elm is focused on simplicity and giving just enough to do a great job. Roc, being a descendant of Elm, is quite similar. It wants to enable simple, clean, and enjoyable pure functional programming without the complexity that tend to come with these types of languages. Roc also has a few different focuses that will lead to a very different experience, but only time will tell how well they will pan out. The biggest two focuses are the editor and the separation of platform and application. I would definitely advise looking at "The Edges of Cutting-Edge Languages" talk. It focuses on the platform/application boundary. To summarize it simply, instead of giving all permissions and possible side effects to every application, an application depends on a platform that defines what side effects it can produce. A Cli platform may enable reading and writing to standard out, but not arbitrary calls out to the internet. This is nice from a security perspective, but not necessarily what I would consider most important about this separation. I think the 2 biggest gains from the platform/app separation are a clear api, and a clear pure functional section of code. When it comes to api, a standardize web platform api could be created that most web servers use. Then, as an author that is writing a roc app with that api, I now have the freedom to switch between any web platform that fulfills the api. The platform could be implemented with Rust and warp. It could be C++ and drogon. Any language that can do C FFI could technically be my platform. Then lastly, the clear pure functional section of code makes Roc a lot more readable, debug-able, and testable. Look at some popular elm talks, it is a common theme of how nice this is. Simply put, if a function doesn't return a Task, it can't do any side effects. The function signatures can often guide you to which functions it is even possible to produce the bug you are seeing. Haha, this is longer than I thought it would be. Hopefully it helps add some context.
He actually has a talk speaking about this (ua-cam.com/video/vzfy4EKwG_Y/v-deo.html) basically, it's creating a language that is as pleasing to use as elm, but for general use, performant, and production ready instead of academic, all while still being a pure functional programming language
I think this was mis-spoken if it was said in the talk. A non-exhaustive pattern matching will produce a compilation error. That being said, roc will try to compile any program to help with debug-ability. Thus it will still compile the non-exhaustive pattern match such that it will produce a runtime error if the pattern is hit.
34:15 Ah, that's just a monoid in the category of endofunctors, what's the problem? Edit: Do you do optimizations like Haskell's ApplicativeDo pragma, or Scala's BetterMonadicFor compiler plugin, where sometimes you can desugar into .map or .apply calls instead of .flatMap (or >>= "bind")?
there is no bind. Look again. It's way simpler and general. - If you want bind, you must supply it each time (here, it was await) - If you put flatMap, I'm sure some optimizer can easily notice it (in the future, when implemented), but you could also just write: x b) -> List b
@@Verrisin at 36:29 he goes into 'backpassing' which is sugar for Task.await calls. My question was whether backpassing can also desugar into .map or .apply calls instead of flatMap/await (like Haskell's ApplicativeDo and Scala's BetterMonadicFor)
@@Jankoekepannekoek Let me repeat: There is no bind. (as part of desugar) Look again. -- The await is here analogous bind, and you have to supply it on each line. - It's _only_ transforming the rest of the "function body" into a callback. - Result of the whole expression will be whatever the function after the first
The reason that made me hate Elm: the forced formatting style. - It's absolutely unusable. I would need 3 vertical stacked monitors to see more than 10 useful lines, and even that would not be useful, because you want code CLOSE TOGETHER so your eyes can parse above and below. If you put empty lines between everything, it becomes super hard to read. And you do not see the overall patterns in the code. - As much as I like this language, when he said it has forced built in formatter based on Elm ... that's really bad. - At least give 2 options: perfectly-regular and usable-condensed . - The fact I cannot have single line functions, or 3 one-line statements on 3 lines is mind bogglingly stupid. 2 let statements take 5 lines at least! And it's all over the place... So, this one thing scares me...
I'm not sure I understand the point of having different platforms. What if I want a cli application that's also a web server? The other strange thing is the type alias syntax. If `term : Type` means "term has type "Type", then you might expect `Boolean : [True, False]` to mean "Boolean has type "[True, False]". But of course, that's not correct. In fact Boolean (which is itself a type) doesn't have type "[True, False]", it is *equal* to "[True, False]". So why the departure from prior art, why not just use the `=` sign for type aliases as other languages have done?
No offense but. I like Richard Feldman, he is very good presenter. He had been working for a long time with Elm, now he decided to create his own functional programming language. How is Roc different than Elm?
I feel confident in saying that the set of strictly positive integers sees less than 1 percent of the use that the set of nonnegative integers sees in math, and that the phrase "natural numbers" refers to the latter in essentially every mathematical context. Even the integers themselves are traditionally constructed from the naturals
@@thomasporter4627 With due respect, you confidentiality has nothing to do with math science :) To be not confident but sure, you only need to go and find its definition :) Cheers
Would be nice if you could pipe multiple async tasks and not just two, and also pass multiple async tasks in a list for parallell execution. I felt it is a bit weird if some type names are abbreviated but not others?
"Would be nice if you could pipe multiple async tasks and not just two" What specifically are you referencing here? "and also pass multiple async tasks in a list for parallell execution" Totally doable if the platform decides to support it. Not really a roc limitation here.
@@brendanhansknecht4650 I think i was referring to Task.await which seem to take two async tasks, and that it would be neat if you could chain more than two. Maybe you can, not familiar with the language.. Looks really promising though.
It looks like a nice language. I’m not a fan of using “cute syntax” though, like using symbols instead of text. Such as using \ instead of “fun” or “function”. Not all keyboards are American, and while a keypress combination might be trivial, or a “one press” key on your keyboard might be unusual on a different keyboard. Particularly for symbols which are not as commonly used. (On my Swedish iPad keyboard the symbol isn’t even written on the keyboard, so I had to experiment to find it.) One thing that is typically always available is letters. Also, “cute syntax” is often a lot harder to Google. And it’s harder to parse the text if you are unfamiliar with the language. For people familiar with functional programming the -> is a hint that its a function. But for programmers unused to this convention it may not be obvious at all that it’s a function at first. In conclusion, please don’t be like Perl with cute syntax. ;-) The language itself looks nice though!
I wonder if some wise person has invented the sort of reciprocal to Greenspun's 10th rule. Any pure functional language will eventually implement procedural algorithmic features corresponding to stateful variables and sequential execution. (And it will look worse than Fortran.)
Why would someone use this vs F#? The syntax seems a mix of Haskell and OCaml. A bit of an odd decision to leave out currying. The lack of a package manager is going to be a big thing for adoption curve.
It’s funny. I work in a Python shop, and my first impression of languages I hear about is how easily I’d be able to get my boss on board with it. The white-space scoping, str keyword, and simple square-bracket lists are familiar elements that immediately made me go, “Oooh. This might have a chance!”
I was really excited until I learnt it's a direct descendant of Elm so.. probably no typeclasses? That's going to be a showstopper for a good developer experience..
Haskell is already perfect, and it's hard if not impossible to improve on perfection. Instead of trying to make a new and improved Haskell, why not write a Haskell compiler on top of Rust that doesn't need garbage collection?
As much as I love Haskell - it's definitely _not_ perfect. And those things Roc does different from Haskell, they make a lot of sense to me. In particular the tag mechanism is something where I often thought, _I whish this was possible_ in Haskell (without some really tricky TH hackery). The other differences seem to be mostly superficial, but could nevertheless be quite an improvement for practical development.
@@leftaroundabout Anything is possible in Haskell, and Roc appears to be slightly less logical and intuitive than Haskell, from what I saw in the video. The only thing that can be improved is to implement the static memory management system of Rust in Haskell, to eliminate the need for dynamic garbage collection.
@@coldsteel2105 currying is hardly more or less “logical” in any meaningful way, it's just a bit different. I wouldn't want to work in a language that doesn't support currying, but clearly, both Haskell and Roc support curried as well as uncurried functions - it's more a matter of what's the standard style. Both have advantages and disadvantages, and Roc seems to have given careful thought to getting the advantages of currying without needing to curry _everything by default._
@@leftaroundabout For example, you accomplish the same purpose of tags with pattern-matching, something the vast majority of programmers are already familiar with. Unlike Haskell, Roc doesn't use currying for functions, making it less logical. The syntax that Roc uses to concatenate strings is less intuitive than it is in Haskell; Haskell treats strings just as a list of characters. Finally, the syntax for defining a function in Roc is not intuitive whatsoever. Haskell comes the closest to implementing rules and syntax of mathematical logic in a programming language.
@@leftaroundabout Currying is more logical, because that's how you solve functions in mathematics. Haskell follows the rules of math instead of re-inventing it's own rules.
@@cranknlesdesires Performances? Haskell almost has C-like performances. So nothing new. And Elm is just very opinionated, that's what people like (and dislike) about it. The whole point of Elm is just its very focused library and the compilation in JS. It's not new, nothing is new in the language, just convenient for this very specific goal. That's it. Roc is yet another Haskell clone. Nothing in this video is new.
@@beauteetmusculation8191 Haskell doesn't have C like performance, nor java like performance. It's hard to reason around its GC and lazy eval makes reasoning around program performance harder than it should be. Roc is a ML type language, like haskell and the long family of MLs but its not the samething. I was not saying any particular feature is new, its the combination of features, included and excluded, and implementation that makes it unique and gives it an edge of something like Haskell. I would recommend watching the presentation on roc's performance for more of a understanding on that front.
@@cranknlesdesires Lazy eval can just be dropped if you don't want it. That's simply not an argument. You clearly have a hard time thinking about it to get efficient code, that's fine, nobody ask you to write code in Haskell. But telling people that's not efficient just because YOU don't like Haskell (or can't make it fast) is straight up bullshit.
HOW IS THIS LANGUAGE BETTER THAN THE SECRET LANGUAGE MY MISTRESS AND I INVENTED TO TALK ABOUT SEX SO THAT MY WIFE AND FAMILY ARE NONE THE WISER. BECAUSE LET ME TELL YOU IT IS VERY ADVANCED.
So, basically "roc" steals A FREAKING LOT from Haskell. I wonder why bother creating the same language, just improve on what's already here. I would have loved new compiler options to get Haskell running on massively constraint platforms, maybe dropping the garbage collector to have a fixed-size memory array for the whole program, or a change in the optimization processes to provide guarantees on stack sizes, idk. Or improve on other languages, a lot simpler for common folks, like Lisp or scheme. Same stuff.
Roc isn't that like haskell, haskell is much broader of a language, has some cruft, a bloated standard library (how many folds does it have and which one is the most performante), and can't give the same experience and insurances that Roc's inspiration, Elm, does. Although superficially similar Roc is quite a bit more simple and less overloaded than Haskell, taking many of the good ideas while leaving some of the missteps behind. This can be said of Roc and many other languages(F#, *ML, etc)
@@beauteetmusculation8191 look, I know you've invested a lot of time into Haskell and can't imagine much beyond its walls but I would recommended branching out, live in Ocaml, F#, a scheme, Agda, Erlang, a Array language like APL or J, even that strange world of C++ gpu programming. Although superficially having the same or similar features as Haskeln, they are not the same and have unique quirks and encourage vastly different methods than what you're used to.
No constructive feedback just offensive speech. I have enough of such comments so I reported it. If you care about making the world a better place I encourage you all to do the same.
@@marcziel5424 @declup @TankorSmash OP didn't mean BAD in the litteral sense. I guess, He meant bad in the good sense. Here is what google says about Bad as slang. "Bad" means good. Actually "bad" means even better than good. It's often used in reference to someone's appearance.
Everything this guy presents I’m automatically hooked into. What an impressive and talented speaker
Wait till you hear about his rusty spoons collection!
I like the generalization of `Unit` type (type that has only one value) as empty product type (`{}`) and `Never` type (type that has no values) as empty sum type (`[]`). While it is quite common to represent unit type with empty tuple in many programming languages, it never occured to me that never type could be represented with empty union - but it totally makes sense.
The "never as empty sum type" generalization is quite smart
This is exactly what rust has been doing since forever and what it encourages. Something like Infallible in the std is exactly defined as an empty enum so compiler knows it has no possible values
@@DeerDesigner why is that when Rust has dedicated "never" type (`!`)?
You can read more about that on Bob Harper's Practical Foundations for Programming Languages book, it's a well-known way of defining absurdity in PLT.
@@uwundrej because in Rust, you can't have nameless sum types, so you can't cleanly define an empty sum type that will play well with other empty sum types
As someone who loves F# I have really enjoyed your video!
this looks like Haskell but geared towards practicality. Super excited about this!
Great stuff RT, lots of intelligent stealing, looks like your goal is to be as happy writing general apps as you would be in elm.
He did a really nice job, not getting into the Functional jargon… The way he explained Bind, was very smooth :-) Well done !
do notation without talking about it. Nice 👍🏿
@@aly-bocarcisse613 I consider this superior to do notation, because the bind is not baked in.
- Yes, you have to provide it on each line, but also you can arbitrarily combine without worrying with ugly things like monad transformers.
The backpassing syntax, yes! I've always wanted that!! -- Exactly that feature.
- Just "wrap the rest of the body in a closure" and nothing else. Scala almost has it in for loops, but still quirky. Monad do syntax forces using bind for no reason. All one wants is this rewriting. Putting the bind manually at the start of each line is fine, and importantly it lets me easily combine different monads, instead of the crazy mess in Haskell.
- Much more general and useful than the "async/await" syntax everybody is incorporating stupidly. .... Yes, yes, it's slightly faster, and it works better with loops and mutable variables - hence disallowing multiple invokes of the continuation, etc.... I get it. But this is so nice and useful!
Great talk! Roc seems to be very exciting. The backpassing concept and syntax is particularly elegant.
The backpassing for await is very similar to a very powerfull mechanism in F# which is called “computational expressions”. Which is also a some kind of syntactic sugar in F#.
That's more like do notation and you have to specify pure/bind for every monadic type.
so this language has tag unions, which are not to be confused with tagged unions. Except they also can be tagged unions, because the tags may have associated types. got it
This is so close to being my favourite language. Just needed curried point-free composition.
For whatever reason this language is very appealing, there is a subtly in it. I will definitely be on the look out for it's progress, and will likely spend much time grasping the ins and outs.
Why editor instead of a language server?
There are so many QoL things you will never have time to implement yourself.
I am almost certain there will eventually be a language server, but Roc is trying to do some really innovative things with the editor. We have a large focus on developer experience and are trying to push boundaries in ways that wouldn't fit into a language server. That is why we are building an integrated editor.
Richard talks about it here: ua-cam.com/video/cpQwtwVKAfU/v-deo.html
His argument is that the ceiling for how much help a language-specific editor can give you is much higher compared to a plugin.
Examples he brought were Visual Basic, SmallTalk, Pharo and Dark.
Definitely a lot of reinventing the wheel on common editor features though, I hope it won't distract too much from the development of the language itself, pretty excited about it!
note that language servers are also quite painful to implement, and quite restrictive. so it's very, _very_ far from idedal too.
Very interesting language. I've been collecting design ideas for a potential future language and it's uncanny how many design decisions overlap with what is here.
So... you just like Haskell. Fine. That's a great language. :)
@@beauteetmusculation8191 You must not write much Haskell.
I love how backpassing lets you basically implement Promises with 1 line of code 😄✌️
He even has fully AST aware editor! - Roc has most of the things I wanted to do in my potential language, if I ever had the time for it!
Congrats on progress so far RF. Looking forward to using it.
the only problem with Result is, that it doesn't show where the problem happened.
- While I love tail call optimizations and many things .... in large projects, I don't think I would be able to find errors in a reasonable timeframe without stacktraces...
- Yes, I could wrap everything in very specific tags, but then I would still not know the call chain, and the bug is often 20 calls higher ... (as in: oh, the url was wrong, nice it was included in the Result, but why was it wrong? and that is still a simpler case to find)
- This does not work well with any async system (unless it tracks it explicitly; or go-like green threads), and I dislike stacks ... but I wish there was a good solution to this... somehow building the stack-trace as part of args ... but that would be slow ...
Anyway, language looks really nice!
seeing this, roc might be the first language where WASM module might becomes a first class and for stitching other language
What about Zig? It can compile to WASM from about day one.
@@beauteetmusculation8191 zig and rust are might be more like where your WASM "syscalls" where going to be implemented and where roc might be the stitcher, it also map nicely with how platform concept mapped to those WASM "syscalls".
Not even a fan of Function Style Programming and space indentation
But this looks so good.
So much thought was put into this.
It all feels so cohesive and well designed.
Kudos
Great talk. LiveScript (untyped, transpiled into JS) has backpassing (called backcall)
I'm wondering how do you handle error unions that has clashing definition? Say I have two function f and g, f can throw an (ErrorX Int) while g can throw (ErrorX String), and (await f g) should result in compile error since Int and String is not dimcriminatable, in this case do I have to map one of them to use a different constructor?
There is no issue in roc making a function that returns (ErrorX a) where a can represent any type. So the wrapping function that calls g and passes it's result to f would first await on g, potentially returning (ErrorX Int). If it doesn't fail, it will give the unwrapped result to f and await on f. Then if f fails, it will return (ErrorX String). Finally if nothing failed, it would return the overall result.
ErrorX [Int, String]
Can’t wait to give this a try!
Dylan Thomas in his poem Fern Hill was both green and gold(en).
Great talk!
Roc looks very like ReScript or OCaml :)
Looking forward for Roc to become public!
2:05 SIDE EFFECT!! 😱
just kidding.
Nat is a very useful type! Thanks! And very clever to register the "platform" as a plugin which the code uses! That is very good design imo.
But some things seem strange to me:
* why do you type annotate function parameters as if the function is an n-ary function? Isn't partial application a thing in Roc? If yes, I definitely prefer Elm's syntax which makes clear, that we always get back a unary fn!
* why are Union types written as lists? Can you iterate them?
* why does List.get first take the list and then the index in contrast to Elm?
* why do you distinguish between constants and functions which take no arguments and always return the same thing like in Elm? Is it because the syntax is more streamlined this way when you declare anonymous functions (which you had to write like this \arg -> body in Elm)?
@10:51 I don't understand how Roc could possibly be introduced as a direct descendant of Elm if it's not curried.
Why is that a requirement to be a descendant? Sure that is a feature in Elm, but Elm as a language is not defined by currying.
That language look so good !
Thank you for avoiding M-word
What's the M-word?
@@LNTutorialsNL M*nad
The first thing I thought when I saw the type signature of Task.await was that it was the bind operation of a monad.
he also avoided the do notation (aka backpassing early years)
@@LNTutorialsNL M*nad
String interpolation in Roc looks a lot like Swift's: "Hi \(name), you are \(age) years old" 🤓
It makes sense to me. I would use the same, if I was making a language. Why use a different escape? \( already doesn't (shouldn't) mean anything, and () means clearly specifying bounds of an expression. It's the most sensible syntax.
- The only reason to use something else is for direct identifiers like "asd $a asd" which is useful, but has caveats. \() forces using () always, but is nice otherwise.
Cool! One thing: I'm not seeing how backpassing is distinguished from Haskell's do notation. Am I missing something?
Yes. Backpassing exists without the need for a monad type class or even a bind operator.
@@dobotube I see. But essentially the "callbacks" are necessarily monadic operations over certain types which would support them, are they not?
@@nijibabulu I don't think so. It's sugar for anything that can be written in continuing passing style.
I had the same confusion, guessing he left it out of the talk for time consideration. Their backend is haskell so I'm guessing they've heard of do notation lol.
I'm not sure it's better than monads in an abstract sense, but maybe they feel it's a lot easier to understand than monad operators, classes and instances. Remember Elm is really opinionated, Roc is going to be following in that ethos where FP needs to be accessible to newcomers.
I consider this superior to do notation, because the bind is not baked in.
- Yes, you have to provide it on each line (here called await for tasks), but also you can arbitrarily combine without worrying with ugly things like monad transformers.
It looks really cool, but two things bother me, why is the language not curried and why do you use so many abbreviations? I know that the abbreviations thing is very common in functional languages, but is it really so much faster to type "Str" and "Err" instead of "String" and "Error" in an IDE with autocompletion?
Must agree with you on the abbreviations... I could have been doing functional programming back in the 1980s if I hadn't been so turned off by LISP's annoying and meaningless abbreviations for everything.... I could have been doing functional programming in the early 2000s if I hadn't been so turned off by Haskel's annoying and meaningless symbols for everything............. ;)
JavaScript is flawed in so many ways but, in JS, I can write functional code and then read it back like an articulate human being instead of a malfunctioning android reading SMS messages.
V is guilty of this as well, some other recent languages too... I don't know why this bad practice seems to have returned in recent years for some reason. It seems to signal somebody valuing "coding fast" above "readable code" - but as you said, IDE autocompletion, so even that doesn't make any sense. Perhaps some of these people code in text editors - since they're working on new languages that may not have any substantial IDE support yet, a combination of those two factors might be the explanation. It's misguided either way. 😕
Could not agree more, we use languages as an abstraction for not doing machine code directly, if you really need to save some bytes by writing Err instead of Error, then you probably need assembly more than a high level language. Let's keep it human and readable, even if this means this is a mouthful to read, explicit is better than implicit.
I assume that currying is difficult because functions are not boxed
re: OP - it's not about autocompletion
re: readable, thats wrong imo.
re: haskell's symbols, i think those are awfult oo.
re: coding fast... i honestly don't think it improves programming speed in any significant way at all. so it can't possibly be for them to type things faster.
short names are more readable, especially in long lines made up of say, just four lines
it's a lot easier to find Err than it is to find Error which is ~60% longer. granted, it's a bit contrived in this case but it's a lot more important in functions like getOr vs getOrDefault.
even more important, after a certain point i feel like it's more a chore having to read the full method name... e.g. "concatenate" vs "concat". as long as it's _extremely_ clear what it refers to i really don't see how it's _not_ a good thing for readability.
re: let's keep it human and readable, explicit is better than implicit... it _is_ explicit. but just because you speak english doesn't mean programming languages are also english.
i remember using "backpassing" in coffeescript and livescript to get out of callback hell before async/await existed
great video and an interesting language. thanks
Thanks for the demo!
I'm not sure, aside from compiling to wasm, what this language innovates on?
All these features existed in Scala for example for absolute ages, especially the "I haven't seen it anywhere" Backpassing, which existed in Scala for years and is called for-comprehension. The syntax is just identical.
Seems a lot like Haskell. Could you elaborate pros/cons vs Haskell?
haskell is a research language that is a bit anti-beginner and has some pitfalls, like strings being linked lists.
if I understand right, roc is trying to orient toward business use where performance is an asset.
@@CaptainWumbo Meh. Strings are rarely used in real life, Text is. Performance is there already.
I generally prefer languages with a less good type inference 😅, but this seems great!
How does one separate Tags from other types? Are there no other types?
- I can imagine List being defined as List a : [ Nil, Cons a (List a) ] ... but then what is List.map ? Is the function somehow defined on the Union ??
- Are Tags namespaced? It seems like they are not, which would bite one in bigger codebases...
I’m guessing that the creation of this language signals that his experience at NoRedInk convinced him that Haskell is just “too much” for the average backend developer. Or maybe that Elm+Haskell was too great an impedance mismatch.
I don't think that is it. I think it is more so that Elm is a lot more fun for most people to develop in. It is simply a much nicer and more catered experience (of course more limited as well). With that in mind, many people have wanted Elm for systems level programming for a long while. I think this is more about the great Elm experience than Haskell being "too much" or "too complex" for must developers.
Why are arguments comma separated in function definition? It seems painfully different from function application.
I'm only 8 mins in.. And I am so excited about this. Lol. This seems a lot like.. F# on bare metal. With order independent declaration.
Why type annotation and type alias have the same syntax?
Does look weird. Would rather have an “alias” keyword
@@AdrianBoyko they seem to try to avoid keywords as much as possible. The `:` is already reserved anyway, and `UppercaseIdentifier : ExistingType` can't possibly be a signature, so _why not_ just define this to denote a type alias?
ok, but how are the platforms implemented? - some native code? like Rust / C++ ?
What is the difference between backpassing and the do notation for monads and applicative functors? It doesn't seem new at all.
To me it seems that it is just syntactic sugar, for anonymous functions, and not bound to monads or applicatives, like do notation (And as someone else pointed out in another comment, do notation has an implicit >>= in Haskell). So from what I understand, backpassing could be used for any higher order function, which takes the function as the last argument.
Ha yes, if it is more generall than applicative/monadic bind, it might be really interesting.
It's a general-purpose syntax for continuation-passing style, which means it does need the monad bind operator (e.g. Task.await) explicitly writing on each line.
An interesting idea indeed.
@@SimonClarkstone But I thought CPS was monadic so same-same
Haskell is also going in the direction of having a CPS engine builtin for faster effect management. It’s not interesting in terms of generalization, but generalization is most of the time not the interesting thing in language design.
An interesting language, and it has an ergonomic Elm-like syntax. May I ask, though, what the language's motivation is, when other similar languages, like Elm, Purescript, Haskell, Typescript, ReasonML, SML, Idris, and (maybe) Elixir, already exist?
I can't speak for Richard, but I think this programming language fills a niche that doesn't necessarily overlap with most of the languages you listed. Firstly, Elm, Purescript, Typescript, and ReasonML are very web frontend targeted. Though Roc can compile to web assembly and thus make a web frontend, that is not really the main focus or target. If you want to make a web app with a extremely nice pure functional language, Elm already has that space covered.
I don't know SML or Idris, but to my understanding SML, Idris, and Haskell are the languages the overlap the most with Roc. I think one core difference between Roc and those languages is the same difference between Purescript and Elm. Purescript is extremely powerful, very academic, and quite daunting, while Elm is focused on simplicity and giving just enough to do a great job. Roc, being a descendant of Elm, is quite similar. It wants to enable simple, clean, and enjoyable pure functional programming without the complexity that tend to come with these types of languages.
Roc also has a few different focuses that will lead to a very different experience, but only time will tell how well they will pan out. The biggest two focuses are the editor and the separation of platform and application. I would definitely advise looking at "The Edges of Cutting-Edge Languages" talk. It focuses on the platform/application boundary. To summarize it simply, instead of giving all permissions and possible side effects to every application, an application depends on a platform that defines what side effects it can produce. A Cli platform may enable reading and writing to standard out, but not arbitrary calls out to the internet. This is nice from a security perspective, but not necessarily what I would consider most important about this separation.
I think the 2 biggest gains from the platform/app separation are a clear api, and a clear pure functional section of code. When it comes to api, a standardize web platform api could be created that most web servers use. Then, as an author that is writing a roc app with that api, I now have the freedom to switch between any web platform that fulfills the api. The platform could be implemented with Rust and warp. It could be C++ and drogon. Any language that can do C FFI could technically be my platform. Then lastly, the clear pure functional section of code makes Roc a lot more readable, debug-able, and testable. Look at some popular elm talks, it is a common theme of how nice this is. Simply put, if a function doesn't return a Task, it can't do any side effects. The function signatures can often guide you to which functions it is even possible to produce the bug you are seeing.
Haha, this is longer than I thought it would be. Hopefully it helps add some context.
The intent was afaik elm but for non JavaScript targets. So for RF specifically it may someday replace their backend language
@@brendanhansknecht4650 ReasonML is mostly OCaml with JS syntax. So it works for backend. But adoption is limited.
He actually has a talk speaking about this (ua-cam.com/video/vzfy4EKwG_Y/v-deo.html) basically, it's creating a language that is as pleasing to use as elm, but for general use, performant, and production ready instead of academic, all while still being a pure functional programming language
A pure functional language with the speed of an imperative language and no gc pauses. None of the languages you mentioned have all three AFAIK.
Non-exhaustive pattern matching is a *runtime* error? Shouldn't this be covered by static analysis?
It is. You get an error message
@@AdrianBoyko the error message on screen said "runtime" 🤔
IIRC, the compiler said that the error could lead to a runtime exception if not corrected.
I think this was mis-spoken if it was said in the talk. A non-exhaustive pattern matching will produce a compilation error.
That being said, roc will try to compile any program to help with debug-ability. Thus it will still compile the non-exhaustive pattern match such that it will produce a runtime error if the pattern is hit.
@@brendanhansknecht4650 the word "runtime" is in the error message on screen. Could have been the error message was incorrect, I guess?
34:15 Ah, that's just a monoid in the category of endofunctors, what's the problem?
Edit: Do you do optimizations like Haskell's ApplicativeDo pragma, or Scala's BetterMonadicFor compiler plugin, where sometimes you can desugar into .map or .apply calls instead of .flatMap (or >>= "bind")?
there is no bind. Look again. It's way simpler and general.
- If you want bind, you must supply it each time (here, it was await)
- If you put flatMap, I'm sure some optimizer can easily notice it (in the future, when implemented), but you could also just write:
x b) -> List b
@@Verrisin at 36:29 he goes into 'backpassing' which is sugar for Task.await calls. My question was whether backpassing can also desugar into .map or .apply calls instead of flatMap/await (like Haskell's ApplicativeDo and Scala's BetterMonadicFor)
@@Jankoekepannekoek Let me repeat: There is no bind. (as part of desugar) Look again. -- The await is here analogous bind, and you have to supply it on each line.
- It's _only_ transforming the rest of the "function body" into a callback.
- Result of the whole expression will be whatever the function after the first
@@Verrisin ooh. I see. Thanks, I get it now!
The reason that made me hate Elm: the forced formatting style.
- It's absolutely unusable. I would need 3 vertical stacked monitors to see more than 10 useful lines, and even that would not be useful, because you want code CLOSE TOGETHER so your eyes can parse above and below. If you put empty lines between everything, it becomes super hard to read. And you do not see the overall patterns in the code.
- As much as I like this language, when he said it has forced built in formatter based on Elm ... that's really bad.
- At least give 2 options: perfectly-regular and usable-condensed .
- The fact I cannot have single line functions, or 3 one-line statements on 3 lines is mind bogglingly stupid. 2 let statements take 5 lines at least! And it's all over the place...
So, this one thing scares me...
I'm not sure I understand the point of having different platforms. What if I want a cli application that's also a web server?
The other strange thing is the type alias syntax. If `term : Type` means "term has type "Type", then you might expect `Boolean : [True, False]` to mean "Boolean has type "[True, False]". But of course, that's not correct. In fact Boolean (which is itself a type) doesn't have type "[True, False]", it is *equal* to "[True, False]". So why the departure from prior art, why not just use the `=` sign for type aliases as other languages have done?
Should it have been `Str.isEmpty info.greeting` at 11:30ish?
Yes, that would be the equivalent of the record destructuring example.
No offense but. I like Richard Feldman, he is very good presenter. He had been working for a long time with Elm, now he decided to create his own functional programming language.
How is Roc different than Elm?
This is actually really cool! Is it functional?
great work! Am i the only one too picky to mention that natural numbers actually do not include 0?
We use the oxford defintion???🤣 "the positive integers (whole numbers) 1, 2, 3, etc., and sometimes zero as well."
@@brendanhansknecht4650 I'm not sure if Oxford vocabulary can be considered an authority when it comes to math :D
I feel confident in saying that the set of strictly positive integers sees less than 1 percent of the use that the set of nonnegative integers sees in math, and that the phrase "natural numbers" refers to the latter in essentially every mathematical context. Even the integers themselves are traditionally constructed from the naturals
@@thomasporter4627 With due respect, you confidentiality has nothing to do with math science :) To be not confident but sure, you only need to go and find its definition :) Cheers
Would be nice if you could pipe multiple async tasks and not just two, and also pass multiple async tasks in a list for parallell execution. I felt it is a bit weird if some type names are abbreviated but not others?
"Would be nice if you could pipe multiple async tasks and not just two"
What specifically are you referencing here?
"and also pass multiple async tasks in a list for parallell execution"
Totally doable if the platform decides to support it. Not really a roc limitation here.
@@brendanhansknecht4650 I think i was referring to Task.await which seem to take two async tasks, and that it would be neat if you could chain more than two. Maybe you can, not familiar with the language.. Looks really promising though.
@@erlend1587 No. It only takes one task, and a continuation.
a
11:27 Looks like a bare "greeting" should be info.greeting
why another lang?
It looks like a nice language. I’m not a fan of using “cute syntax” though, like using symbols instead of text. Such as using \ instead of “fun” or “function”. Not all keyboards are American, and while a keypress combination might be trivial, or a “one press” key on your keyboard might be unusual on a different keyboard. Particularly for symbols which are not as commonly used. (On my Swedish iPad keyboard the symbol isn’t even written on the keyboard, so I had to experiment to find it.) One thing that is typically always available is letters.
Also, “cute syntax” is often a lot harder to Google. And it’s harder to parse the text if you are unfamiliar with the language. For people familiar with functional programming the -> is a hint that its a function. But for programmers unused to this convention it may not be obvious at all that it’s a function at first.
In conclusion, please don’t be like Perl with cute syntax. ;-) The language itself looks nice though!
i think natural numbers start with one
I would have used the title 'Piece of the Roc'
Maybe I am too old... ;-)
my only nitpick would be that declarations are case sensitive
What are you writing in today? Pascal??
So * is just a wildcard, you could've said that :)
I roc-k with this language FR 🔥
I wonder if some wise person has invented the sort of reciprocal to Greenspun's 10th rule.
Any pure functional language will eventually implement procedural algorithmic features corresponding to stateful variables and sequential execution. (And it will look worse than Fortran.)
Why would someone use this vs F#? The syntax seems a mix of Haskell and OCaml. A bit of an odd decision to leave out currying. The lack of a package manager is going to be a big thing for adoption curve.
I wish they rename {} to one of None, Nil or Unit and [] to Never
Love the language, hate the «Str» (*Stuurrr*) decision 🙈
It’s funny. I work in a Python shop, and my first impression of languages I hear about is how easily I’d be able to get my boss on board with it. The white-space scoping, str keyword, and simple square-bracket lists are familiar elements that immediately made me go, “Oooh. This might have a chance!”
Why do you spell it as Roc and not Rock?
A Roc is a mythological bird, thus the bird logo.
I was really excited until I learnt it's a direct descendant of Elm so.. probably no typeclasses? That's going to be a showstopper for a good developer experience..
Very cool
Why settle for a custom editor when you could have a custom keyboard (as the Sinclair ZX SPectrum had for BASIC) ;-)
Haskell is already perfect, and it's hard if not impossible to improve on perfection. Instead of trying to make a new and improved Haskell, why not write a Haskell compiler on top of Rust that doesn't need garbage collection?
As much as I love Haskell - it's definitely _not_ perfect. And those things Roc does different from Haskell, they make a lot of sense to me. In particular the tag mechanism is something where I often thought, _I whish this was possible_ in Haskell (without some really tricky TH hackery). The other differences seem to be mostly superficial, but could nevertheless be quite an improvement for practical development.
@@leftaroundabout Anything is possible in Haskell, and Roc appears to be slightly less logical and intuitive than Haskell, from what I saw in the video. The only thing that can be improved is to implement the static memory management system of Rust in Haskell, to eliminate the need for dynamic garbage collection.
@@coldsteel2105 currying is hardly more or less “logical” in any meaningful way, it's just a bit different. I wouldn't want to work in a language that doesn't support currying, but clearly, both Haskell and Roc support curried as well as uncurried functions - it's more a matter of what's the standard style.
Both have advantages and disadvantages, and Roc seems to have given careful thought to getting the advantages of currying without needing to curry _everything by default._
@@leftaroundabout For example, you accomplish the same purpose of tags with pattern-matching, something the vast majority of programmers are already familiar with. Unlike Haskell, Roc doesn't use currying for functions, making it less logical. The syntax that Roc uses to concatenate strings is less intuitive than it is in Haskell; Haskell treats strings just as a list of characters. Finally, the syntax for defining a function in Roc is not intuitive whatsoever. Haskell comes the closest to implementing rules and syntax of mathematical logic in a programming language.
@@leftaroundabout Currying is more logical, because that's how you solve functions in mathematics. Haskell follows the rules of math instead of re-inventing it's own rules.
@58:00 IT'S A TRAP!
LOL not pure.
Tags are identical to atoms in erlang, which is a 35 year old language. Not exactly novel lol
The more you scratch the surface, the more you find out that there is no novelty in this language. All done in Haskell, Lisp, Erlang, and the others.
Haskell, Lisp and Erlang don't have a Elm like compiler and the performance that the roc team is supposedly getting.
@@cranknlesdesires Performances? Haskell almost has C-like performances. So nothing new.
And Elm is just very opinionated, that's what people like (and dislike) about it. The whole point of Elm is just its very focused library and the compilation in JS. It's not new, nothing is new in the language, just convenient for this very specific goal. That's it.
Roc is yet another Haskell clone. Nothing in this video is new.
@@beauteetmusculation8191 Haskell doesn't have C like performance, nor java like performance. It's hard to reason around its GC and lazy eval makes reasoning around program performance harder than it should be. Roc is a ML type language, like haskell and the long family of MLs but its not the samething. I was not saying any particular feature is new, its the combination of features, included and excluded, and implementation that makes it unique and gives it an edge of something like Haskell. I would recommend watching the presentation on roc's performance for more of a understanding on that front.
@@cranknlesdesires Lazy eval can just be dropped if you don't want it. That's simply not an argument. You clearly have a hard time thinking about it to get efficient code, that's fine, nobody ask you to write code in Haskell. But telling people that's not efficient just because YOU don't like Haskell (or can't make it fast) is straight up bullshit.
omg, another frickin language ? no thanks ! who made you the expert ?
HOW IS THIS LANGUAGE BETTER THAN THE SECRET LANGUAGE MY MISTRESS AND I INVENTED TO TALK ABOUT SEX SO THAT MY WIFE AND FAMILY ARE NONE THE WISER. BECAUSE LET ME TELL YOU IT IS VERY ADVANCED.
indentation is scope? oh yay...
So, basically "roc" steals A FREAKING LOT from Haskell. I wonder why bother creating the same language, just improve on what's already here. I would have loved new compiler options to get Haskell running on massively constraint platforms, maybe dropping the garbage collector to have a fixed-size memory array for the whole program, or a change in the optimization processes to provide guarantees on stack sizes, idk.
Or improve on other languages, a lot simpler for common folks, like Lisp or scheme. Same stuff.
Roc isn't that like haskell, haskell is much broader of a language, has some cruft, a bloated standard library (how many folds does it have and which one is the most performante), and can't give the same experience and insurances that Roc's inspiration, Elm, does. Although superficially similar Roc is quite a bit more simple and less overloaded than Haskell, taking many of the good ideas while leaving some of the missteps behind. This can be said of Roc and many other languages(F#, *ML, etc)
@@cranknlesdesires Sorry, not convinced at all. That's basically the same language with superficial changes. Nothing in this video showed otherwise.
@@beauteetmusculation8191 look, I know you've invested a lot of time into Haskell and can't imagine much beyond its walls but I would recommended branching out, live in Ocaml, F#, a scheme, Agda, Erlang, a Array language like APL or J, even that strange world of C++ gpu programming. Although superficially having the same or similar features as Haskeln, they are not the same and have unique quirks and encourage vastly different methods than what you're used to.
@@cranknlesdesires Yeah, sorry but your whole message sounds like bullshit to me.
@@beauteetmusculation8191 Thanks for the input, I'll take on board this considered and thorough criticism.
Richard feldman is a snitch
I can't see ROC being a competitor to scripting languages like python, without
1) Array and Object access syntax sugars.
2) Methods.
`list
I would recommend playing around with Elm for a while, it may change your mind.
FYI, that is not a functional way of working with lists
Hmmm....
Wow. So many bad ideas in 1 language
What sort of bad ideas?
I'm as curious as TankorSmash. Would you mind mentioning any of the ideas that you find problematic?
No constructive feedback just offensive speech. I have enough of such comments so I reported it. If you care about making the world a better place I encourage you all to do the same.
@@marcziel5424 @declup @TankorSmash OP didn't mean BAD in the litteral sense. I guess, He meant bad in the good sense. Here is what google says about Bad as slang.
"Bad" means good. Actually "bad" means even better than good. It's often used in reference to someone's appearance.
@@BigBeesNase as a native English speaker it is almost impossible to interpret this use of bad as being good... the OP is probably trolling.
BACKPASSING:
can this used like this?
File.write "response.txt"
yes
It would not be used in that way. Would look like this:
name
@@brendanhansknecht4650 so i need every time naming "variable"?
@@mapuaptu yes.
Since this is just syntax sugar for a lambda, the "variable" is really a function argument for the lambda.
@@brendanhansknecht4650 ok. but original question been -> can we compose?
Very cool but I think the backpassing is a bit odd:
group
This nests the same way as do notation would.
Literally the only difference is that here you write await instead of having an implicit >>=
@@mskiptr i see what you mean. My comment was invalid.
This seems pretty nice actually.
Because it was in the slides. From 34:15, especially at 38:19
```
group
userAdd user group))
```
@@dobotube Oh, I already wrote a response. I'm gonna leave it for anyone else interested
@@dobotube Yeah, it's a bit more general than the do notation (although you need to write `await` all the time). And it doesn't rely on typeclasses