4 ms·
I 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
by internet_points 2y ago
I 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.