Readit News logoReadit News
jazzypants · a year ago
> I won’t fall into the trap of trying to define Monads in this post. Instead, let’s talk about monadic-style APIs – that is, APIs that allow you to do a bunch of things one after another, with the ability to use the result of a previous computation in the next computation, and also allows some logic to happen between steps.

Am I crazy, or did he just give a really good definition of monads in programming? I think that it benefits by not letting itself get bogged down in Category Theory nomenclature which doesn't actually matter when programming.

marcosdumay · a year ago
He described a problem people use monads to solve, not monads themselves.

Haskell people do talk about monadic vs. applicative combinators that are different by whether you can use the results of a previous step on the next ones. But that doesn't have a direct relation with the actual definition of those.

But yes, if you are teaching a programming language that uses monads to someone, you will probably want to explain the problem they solve, not the actual structures. As most things in math, the structures become obvious once you understand the problem.

dkarl · a year ago
It's a good description of one application of monads, which is often helpful to beginners if they have been thrown into real code without yet understanding the "why" of monads. If you look up "railway-oriented programming," you'll find more presentations of it.

I think it is a very practical place to start, especially for programmers who have been thrown into a codebase while still new with monads, because it helps them avoid a common mistake that plagues beginners: accidentally dropping error values on the non-success track. Often you simply want to drop values on the non-success track, and there are convenient idioms for doing so, but just as often, you need to examine those values so you can report failures, by returning metrics on validation failures, by providing the right status code in an HTTP response, etc. Railway-oriented programming is a vivid metaphor that reminds programmers that they need to make a decision about how to handle values on the other track.

bos · a year ago
No, this isn’t a good description of monads. It merely describes a case that shows up sometimes.
jazzypants · a year ago
Dang, when I made this silly, little comment about FP, I didn't expect to get corrected by a legend in the field!

Thanks for taking the time to respond.

cdelsolar · a year ago
A monad is just a monoid in the category of endofunctors, what's the problem?
memco · a year ago
Yin the OOP world I’ve seen this pattern called chaining : usually either method or object chaining.
riffraff · a year ago
Smalltalk (and Dart) also have "cascading" which is method chaining with special supporting syntax e.g. in ST you'd send four different messages to the same object with something like

    scene add: sprite; 
          add: otherSprite;
          setBackGround: stage;
          start
I'm not sure if it matches the "reuse values from previous computation" but it should since messages will affect the object, you just don't have local variables.

pxc · a year ago
It's a style I really enjoy, and it's definitely not exclusive to one language or paradigm, exactly. I see it as more of less of a kind with pipelines in Unix shells, too.

In Scala, a language with OOP heritage and support, plus lots of functional programming features, some of the most common methods you use in such chains are monads.

orthoxerox · a year ago
Not really. The big important part of monads is flattening/unnesting the output.

Basically, if you can convert a `Foo<T>` into a `Foo<U>` by applying a function `T -> U`, it's a monoid. Think `map` or `fold`.

But if you can convert a `Foo<T>` into a `Foo<U>` by applying a function `T -> Foo<U>`, it's a monad. Flattening is "some logic", but not any logic, it's inherent to `Foo<>` itself.

enugu · a year ago
Your point on unnesting is apt but don't you mean functor instead of monoid?
agumonkey · a year ago
It's a good spit, some people used to describe them as "programmable semi colon" but while it's simple, it may be too short for most people to grasp.
RexM · a year ago
I think you just fell into the trap.
atemerev · a year ago
The greatest power of BEAM-based languages is the fully preemptive actor model. Nobody else supports it. This is a superpower, the solution of most problems with concurrent programming.

In Erland and Elixir, actors and actor-based concurrency hold the central place in the corresponding ecosystems, well supported by extensive documentation.

In Gleam, actors and OTP are an afterthought. They are there somewhere, but underdocumented and abandoned.

steve_adams_86 · a year ago
This is exactly what I want from Gleam. It does seem to be under documented and abandoned. Is there any understanding of why? Like you say, this seems like a super power. I see so much potential. A language that’s ergonomic, pragmatic as the author says, great performance, low-ish barrier to entry, etc. It seems like it could be an awesome tool for building highly reliable software that’s not so difficult to maintain.
lpil · a year ago
It is not abandoned, I am the maintainer. The documentation covers the APIs of the package but not the “zen” of the wider OTP framework, for that the official OTP documentation and existing books are recommended.
cassepipe · a year ago
It is a very young language that may explain the why
sodapopcan · a year ago
Are there any articles that do a deeper dive into this? I ask because straight up I've been curious about Gleam, but not enough to do a really deep dive because Elixir is too good and, like Erlang, is a very special kind of dynamic language that doesn't leave me feel too lacking.

As I understand it, there have been a few "high profile" attempts to bring static typing to Erlang, all of which gave up when it came to typing messages. Your comment essentially confirms my bias, but is Gleam making real strides in solving this, or is it poised to merely cater to those who demand static-typing with curly braces--everything-else-be-dammed?

sodapopcan · a year ago
Sorry, the end of my comment is quite reductive. Compiling to JS is pretty nice.
jatins · a year ago
this is Gleam OTP package https://github.com/gleam-lang/otp

I agree it's underdocumented but doesn't seem abandoned (has commits in last week)

lpil · a year ago
Hello! I’m the maintainer of the Gleam OTP library. It is not abandoned or an afterthought.
vfclists · a year ago
Don't be so modest!! You are the creator of the Gleam language as well.
atemerev · a year ago
Hi! Good to hear. Why it is not mentioned anywhere on the main site?
dullcrisp · a year ago
I understand things best by comparing across different languages so don’t take this the wrong way but I wonder if you can help me understand: If say I start a goroutine in Go and give it a channel to use as a mailbox, concurrency in Go is cooperative but it’ll automatically use OS threads and yield whenever it reads from the channel. Does Erlang/OTP do something different? If so what does it do and what are the advantages? Or is it more that the library and ecosystem are built around this model?
throwawaymaths · a year ago
I believe go yields after every function exit. Erlang does the same, but there are no loops (you must use tailcall) so you can't lock up the CPU with a while(true).
vereis · a year ago
Gleam runs on the BEAM
atemerev · a year ago
It does. However, its actor implementation is not built upon Erlang/OTP, and currently is “experimental” and not even mentioned on the main site.
skybrian · a year ago
Gleam's 1.0 release was in May and it's still adding major features.

JavaScript support looks interesting. Browsing the package repo, I don't see how to tell which packages are supported on Erlang's VM, when compiling to JavaScript, or both. JavaScript-specific documentation seems pretty thin so far?

oDot · a year ago
You're right about the lack of FFI-specific docs, but Gleam is such a simple language that it's very workable.

I wrote Vleam[0], which allows writing Gleam inside Vue SFCs, and the experience was pretty good even without the docs.

You do have to sometime read the source of other Gleam packages to understand how things work, but again -- Gleam is so simple it's not too bad of an experience.

[0]: https://github.com/vleam/vleam

lpil · a year ago
Most of the work for this has been done, the main missing piece is surfacing it in the UI, which someone will hopefully pick up soon.
patte · a year ago
This is a very concise overview! I have made a small example chat app [1] to explore two interesting aspects of gleam: BEAM OTP and compilation to javascript (typescript actually). If anyone is interested...

[1]: https://github.com/patte/gleam-playground

rossng · a year ago
The `use` syntax is interesting - don't recall seeing anything similar before. But I'm struggling to understand how exactly it is executed and a glance at the Gleam docs didn't help.

Is the `use` statement blocking (in which case it doesn't seem that useful)? Or does it return immediately and then await at the point of use of the value it binds?

jyjasdfsssd · a year ago
It is syntax sugar for CPS [1].

[1]: https://en.wikipedia.org/wiki/Continuation-passing_style

EDIT: I believe prior art is Koka's with statement: https://koka-lang.github.io/koka/doc/book.html#sec-with

rossng · a year ago
Hmm, it definitely looks more interesting in combination with effect handlers. Still not sure I find it super compelling in Gleam vs just not using callbacks.
taberiand · a year ago
The equivalent in F# is let! (F# computation expressions are quite powerful); in rust the ? operator. Other languages have similar features.

It's syntactic sugar, but the readability is worth it

yawaramin · a year ago
You can do something similar in OCaml (as an operator defined at the library level, not a specialized new syntax): https://github.com/yawaramin/letops/blob/6954adb65f115659740...
giacomocava · a year ago
There's a great article by Erika on use, definitely recommended :) https://erikarow.land/notes/using-use-gleam
eddd-ddde · a year ago
I think it's similar to koka's 'with'.

https://koka-lang.github.io/koka/doc/book.html#sec-with

skybrian · a year ago
Everything after the line containing '<-' happens in a callback.

Since it's a callback, I assume it's up to the function whether to call it, when to call it, and how many times to call it, so this can implement control statements.

I would guess that it also allows it to be async (when the callback isn't called until after an I/O operation).

cprecioso · a year ago
It really reminds me of LiveScript's "back-calls" [1], which were a solution for callback hell in JS.

1: https://livescript.net/#:~:text=Backcalls%20are%20very%20use...

klibertp · a year ago
That was way more than a solution for callback hell. With some plumbing, you could get Continuation monad working! With no further support from the language, too. I really miss LiveScript, it's a shame its development stopped. If only it could emit TypeScript, it would still have a chance to fight back, I think.
fire_lake · a year ago
Gleam looks nice but if an F# comparisons was added, I think that would come out ahead based on the authors priorities.
devmunchies · a year ago
One thing I dislike with erlang based languages (both gleam and elixir) is that they use “<>” for string concatenation.

In F#, “<>” is the equivalent of “!=“. Postgres also uses <> for inequality so my queries and f# code have that consistency.

sodapopcan · a year ago
Ha, ok so I gotta give one of these "that's a really strange thing to get hung up on" responses.

Erlang and Elixir don't overload the `+` operator. In fact, they don't overload ANY operators. If you can forgive the syntactic choice of the operator itself (which I think it pretty fair considering Erlang predates Postgres by a decade and F# by two decades), this allows them to be dynamic while maintaining a pretty high level of runtime type safety. For example, one of the "subtle bugs" people refer to when criticizing dynamic languages (even strongly typed dynamic languages) is the following would work when both args are given strings or numbers:

    function add(a, b) { a + b }
Erlang/Elixir eliminate this particular subtle bug (and it goes beyond strings and numbers) since:

    def add(a, b), do: a + b
will only work on numbers and raise if given strings.

greydius · a year ago
One thing I hate about F# and SQL is that they use <> as a "not equals" operator. In Haskell, <> is the binary operator of any Semigroup instance.
Jtsummers · a year ago
> One thing I dislike with erlang based languages (both gleam and elixir) is that they use “<>” for string concatenation.

Erlang doesn't use <> for concatenation so it's odd to name it in this comment, like that language and its developers have anything to do with your complaint. If it upsets you so much, lay it at the feet of the actual groups that chose <> for concatenation instead.

throwawaymaths · a year ago
Well binaries are <<>> so that's consistent at least. And <<>> is quotation marks in several languages, including French.
amelius · a year ago
I don't like languages that use > a lot simply because if I accidentally paste a code snippet in my Bash shell it is likely to pipe to some file.

Also, <> was != in BASIC, I believe.

PS: Don't paste this comment in your shell.

trenchgun · a year ago
F# inherits <> from ML, which inherits it from Algol, which invented it. But that was actually a bad idea, since it deviates from mathematical practice. To follow math, it would be better to use != as in C and those inspired by it, or /= as in Haskell. Or maybe even =/= if you really want to go for the mathy looking notation.

Elixir uses <> as an operator for concatenation of binaries, (which does form a monoid of course), not to be confused with how Haskell uses <> as a binary operator of a Monoid, but for sure inspired by it. And Gleam picked it up from them, probably, to use for a special case of a list monoid, String. And Haskell created <> for Monoid, because it would be too confusing to use multiplication sign for the binary operation like mathematicians do. It would not be ok in programming context.

gorgoiler · a year ago
Then Gleam (and others) use “|>” when piping with “|” would make more sense, except that’s a bit wise OR, not to be confused with “||” which is… string concatenation (in Postgres).
cipehr · a year ago
The author links to a blog post talking about railway oriented programming in f#.. it might be fair to assume they are aware of f#
munchler · a year ago
All the more reason to include it in the comparison.
munchler · a year ago
I converted the example on the Gleam home page [0] to F#:

    let spawn_task i =
        async {
            let n = string i
            printfn $"Hello from {n}"
        }

    // Run loads of threads, no problem
    seq { 0..200_000 }
        |> Seq.map spawn_task
        |> Async.Parallel
        |> Async.RunSynchronously
        |> ignore
The two are pretty similar, but I would give F# the nod on this one example because it doesn't actually have to create a list of 200,000 elements, doesn't require an explicit "main" function, and requires fewer brackets/parens.

[0]: https://gleam.run/

jorams · a year ago
The creation of a list in the Gleam example is a choice, you could replace 'list' with 'iterator' and it would be lazy.

Dead Comment

steve_adams_86 · a year ago
Wow, this is a great overview. I’ve been playing with Gleam a bit and this was really helpful. I’ll definitely refer to this later.

I’d like to dig into the OTP library (I’m curious if anyone has worked with it much?) and create a state chart library with it, but I’m still firmly in the “I don’t totally get it” camp with a few parts of Gleam. I don’t deny that it’s pragmatic. Maybe it’s more so that I’m not up to speed on functional patterns in general. I was for years, but took a hiatus to write code for a game engine and supporting infrastructure. It was so Wild West, but I kind of liked it in the end. Lots of impure, imperative code, haha.

okkdev · a year ago
Most people use the OTP lib! There's this super useful intro repo: https://github.com/bcpeinhardt/learn_otp_with_gleam
steve_adams_86 · a year ago
Incredible, thank you so much! This is exactly what I need.
conradludgate · a year ago
I've tried to get my head around functional programming and also OTP but I also just never got my head around it.

Functional programming seems too limiting and OTP seems more complicated than I would have hoped for a supposedly distributed concurrency system.

I'm sure it's just a skill issue on my part. Right now I'm way too rust-brained. I've heard lots of things about gleam being good for productivity but I don't feel unproductive writing web apps in Rust but I felt every unproductive trying to write a non-trivial web app in gleam

cdelsolar · a year ago
I agree. I've been trying to learn functional programming for years. My brain just doesn't get it. And I've actually built a non-trivial web app in Elm, and started trying to write one in Gleam and I was very very slow and unproductive. Eventually I gave up and wrote the whole thing in Go + TS for the frontend.

For Gleam I was trying to write the whole FE + BE in the same language - I really like that it can be compiled to JS, and I'm honestly sick of the whole React + seven thousand dependencies game, so I was using Lustre (an Elm-like library for Gleam). And again, I've programmed an app in Elm, after a lot of hair pulling, and in the end I didn't enjoy it that much.

I've gone through tutorials and I don't understand things like types having different wildly unrelated constructors, currying (I didn't notice much currying in Gleam but really disliked it in Elm, I cannot follow past the first or second arrow). For writing the front end of the app, I would make _zero_ progress unless referring to other Github projects (and it was hard to find any since Gleam was so new). Anyway, if someone has a book or something that can teach me this stuff it would be great. I want to use the OTP and a single language for FE/BE that's not JS. I'm not dumb, I've been programming since I was a little kid, but maybe I'm too stuck in imperative models.

giacomocava · a year ago
Yeah FP can for sure take some getting used to before it clicks! I think a great resource for that is Gleam's Exercism track (https://exercism.org/tracks/gleam), not only will it teach you the language but by starting with small-ish exercises it can definitely help grokking FP concepts

And if you feel like you're stuck and need help Gleam's Discord is a great place to ask questions :)

beanjuiceII · a year ago
tried gleam but the fact i have to manually serialize/deserialize things, pretty annoying, that doesn't seem very pragmatic
steve_adams_86 · a year ago
Isn’t manual ser/de pretty common? I like it personally. Being explicit at program boundaries usually means far fewer bugs inside the program. In JS I can pile whatever JSON I want into an object, but eventually I need to throw Zod or something at it to tame the crazy.

Maybe a generic “pile this data into this value and pretend it’s safe” tool might be nice for prototyping.

beanjuiceII · a year ago
i dont think manual ser/de is common at all, and languages like dart where it was used is a massive pain point for people so much that they are adding macros to the language and the first macro they add is for serialization. whats not explicit about saying hey i have a struct this is the data i expect, serialize/deseralize in this shape, validation is a another but separate concern. in javascript you are not doing anything manually so i'm not sure why thats an example?
WuxiFingerHold · a year ago
You either trust the input or you don't. If you don't trust your input you need validation like Zod anyway. Parsing untrusted data without validation in Rust or Go is not much better than in JS. You get the basic types checked, but that's all. You need to validate at the boundaries with Rust or Go just the same as with JS. It seems to me that many bloggers of new trendy languages are not aware of validation. A value for name is a string, but how about the length?
__jonas · a year ago
I agree that the stdlib decoder functions aren't the most ergonomic, but I think people are aware it's a pain point and there is development in that are, these two packages for example:

https://hexdocs.pm/decode

https://hexdocs.pm/toy/

lawn · a year ago
This is the biggest reason I cooled a bit on Gleam and whenever I want to do some backend stuff I'd much rather use Rust (using serde to convert to structs) or Elixir (put it in dynamic maps).

I wish Gleam would implement some kind of macro system, making a serde-like package possible.

wonger_ · a year ago
This is one of the complaints people have with Elm too. Json.Encode/Decode is a pain