5 ms·
> and (c) requires a language feature (sequence points) to disambiguate in which order side effects get executed. With Haskell, we just don’t have to care. Rea
by imoverclocked 2y ago
> and (c) requires a language feature (sequence points) to disambiguate in which order side effects get executed. With Haskell, we just don’t have to care.
Reading up to this point, I had to chuckle a bit. I have struggled with the Haskell type system more than I care to admit; It's almost never "we just don't have to care" when comparing to most other popular languages.
That being said, this article does a nice job of gently introducing some of the basics that will trip up somebody who is casually looking through code wondering what *> and <*> and <* do. As usual, there is a steep learning curve because of stuff like this all over the codebase. If I walk away for a month, I need to revisit >>= vs >> and other common operators before I can be productive. It probably doesn't help that I never actually speak to a human about these concepts so in my head it's always ">>=" and not "bind."
- internet_points 2y agoI try to avoid >>= and >> (or *>) because I know it trips people up; do-notation is more than fine. The exception is when parsing with one of the parsecs where you get a lot of <* and *> usage and all the tutorials use those symbols. But I like <|> , it feels very clear that it has a sort of "or" meaning.
- youerbt 2y agoOne exception for me about >>=, is instead of this: thing <- getThing case thing of writing this: getThing >>= \case Not so much because it is less code, but fewer variables to name.
- tome 2y agoYeah `>>= \case` is a really nice pattern! I use it a lot.
- behnamoh 2y agoYou can pipe into Elixir cases too, and the language I'm developing also allows for this and more. The difference here seems to be that \case is a lambda?
- leifmetcalf 2y agoElixir doesn’t even need a special syntax — it gets Haskell’s LambdaCase as a natural consequence of case being just another function, and the pipe operator always chaining by the first argument. Haskell’s >>= is doing something slightly different. ‘getThing >>= \case…’ means roughly ‘perform the action getThing, then match the result and perform the matched branch’ Whereas ‘getThing |> \case…’ means ‘pattern match on the action getThing, and return the matched action (without performing it). The >>= operator can also be used for anything satisfying the Monad laws, e.g. your actions can be non-deterministic.
- tadfisher 2y agoPedantry: >>= can be used for any instance of the Monad typeclass. GHC isn't sufficiently advanced to verify that a given Monad instance satisfies the monad laws; it can verify that the instance satisfies the type definition, but for e.g. the identity law "m >>= return === m" the instance can still return something violating the law (not something substitutable with m).
- behnamoh 2y ago> ...case being just another function, and the pipe operator always chaining by the first argument. Interesting! I thought Elixir was mostly macros all the way down, like this article shows: https://evuez.net/posts/cursed-elixir.html https://evuez.net/posts/cursed-elixir.html Being able to pipe into def, defp, defmodule, if, etc. is fantastic! But apparently you say at least in the case of case, it's not a macro, and it's just a function which returns a monad—I guess it's the same effect afterall? Is that why people say Haskell can get away with lack of Lisp-style macros because of its type system and laziness?
- leifmetcalf 2y agoI was wrong about this. Case is a macro (a special-cased macro even, defined at https://github.com/elixir-lang/elixir/blob/4def31f8abea5fba44d2d92b11a72f3f9c855efd/lib/elixir/src/elixir_clauses.erl#L236 https://github.com/elixir-lang/elixir/blob/4def31f8abea5fba4...), not a function. It works with pipes because in the AST it's a call, unlike in Haskell where case is its own thing.
- yodsanklai 2y ago> I try to avoid >>= and >> (or *>) because I know it trips people up; do-notation is more than fine Interesting. Probably it's just me, but I first learned monads using >>= (in OCaml), so at the beginning I found the Haskell do notation more confusing (and indentation rules didn't help). >>= is just a function and I understand its signature well. On the other hand, "do" is a syntactic sugar that I sometimes had to "mentally desugar" in some cases.
- youerbt 2y ago> It's almost never "we just don't have to care" when comparing to most other popular languages. Struggling with Haskell type system is not an experience of somebody who has developed an intuition about Haskell type system. Granted, it is not a binary thing, you can have good intuition about some parts of it and struggle with others. I think they way you put it is, while technically true, not fair. Those "most other" languages are very similar to one another. It is not C# achievement, that you don't struggle with its type system coming from Java. This is like people struggling with Rust because of burrow checker, well, they have probably never programmed with burrow checker before.
- SkiFire13 2y ago> burrow FYI it's "borrow" (as in when someone lends something to you) not "burrow" (which is a tunnel/hole)
- withinboredom 2y agoI struggled with the borrow checker because I’m smarter than it is, not because I haven’t worked with one before. Mainly I say “I’m smarter” because I’ve worked on big projects without it and never had any issues. Granted, I’ve only gotten in a fight with it once before giving up on the language, mainly because it forced me to refactor half the codebase to get it to shut up and I had forgotten why I was doing it in the first place.
- tinco 2y agoDid you rewrite the code base into C++ to avoid the borrow checker?
- elbear 2y agoFunny, but I remember the difference between `>>=` and `>>` even though I haven't written Haskell in a couple of years. `>>=` passes to the right the value coming from the left, while `>>` drops it. To give an example, you use `>>=` after `readFile` to do something with the contents. You use `>>` after `putStrLn` since `putStrLn` doesn't return a meaningful value.