3 ms·
This is probably the best resource I've come across for discussing this subject: https://fsharpforfunandprofit.com/posts/elevated-world/ https://fsharpforfunand
by Huggernaut 5y ago
This is probably the best resource I've come across for discussing this subject: https://fsharpforfunandprofit.com/posts/elevated-world/ https://fsharpforfunandprofit.com/posts/elevated-world/
- _ph_ 5y agoThanks, but the article loses me at what this "elevated world" is. It doesn't even try to explain what it is and quickly goes over to F# syntax, which I don't understand. Why is there no explanation in the terms of English, math, and any common programming language? If Functors and Monads are real concepts, they should be describable in the terms listed above, if they are only describably in terms of functional languages, I would consider them a pure artifact of those languages :)
- pests 5y agoThere isn't one unique elevated world, as he goes on to say. Two he lists we are familiar with - options and lists. If you've ever used Option(Some|None) and pulled out a value from Some - the Option is the elevated world, the Some|None is the elevated value.
- aszen 5y agoThere's a problem here as the author himself notes. I can provide you a simple example of a function with monadic interface, you will understand it any language but that will not actually help you to conceptualize the idea of monads and influence your thinking. You will just think that's simple, whats the fuss about it and miss the pattern altogether. Imagine asking the user to provide a number, in most languages you will get a `string | null` value and you wish to get a real number from it by parsing the string if the user entered it. In this case assuming you have a function `parseNo` that goes from `string -> int | null` you can create a special function which takes a `string | null` value along with the `parseNo` function and gives you back `int | null`. S Turns out that function can be defined for many different data types and it has special useful properties. In this case it allows us to compose functions neatly, without having to do a whole bunch of null checks. But in other scenarios it can do a lot more.
- _ph_ 5y agoSounds like you are describing high order functions as they are known from Lisp?
- aszen 5y agoYes higher order functions. A function that takes a function as an argument or returns a function. In lisp you can think of a higher order function as taking data, processing it and then returning it just like any other normal function because code is data.
- loopz 5y agoIn most languages you will lack the Monad type and helper functions, and you'll have available many shortcuts that undermine efforts to set up monadic expressions. So something can behave similarly to a monad, but the type systems don't stop you self-sabotaging your code or misunderstanding good composition. Best way to learn is to learn Haskell deliberately. Better than Go, the language forces you to compose better code, and even learn the values of FP. If one is uninterested in learning CS or expanding one's toolbelt, it'll take some years until industry catches up.
- MauranKilom 5y agoSay you have a source of A, and a way of turning an A into a source of B. An operation that uses these two inputs to produce a source of B is a monad. This is about 90% of the way there (and TFA actually contains very similarly phrased description, right before the monad definition you complained about). The problem is that English does not have the right words to describe the abstract idea behind "source", "way of" and "operation" precisely and rigorously. Regarding "any common programming language": In a way, this is like trying to explain a concept like, say, "the adjoint operator" [0] to someone only aware of integers. Or trying to explain the idea of the Liskov Substitution Principle [1] to someone who just learned assembly. In each case above, the language used to describe the concept is multiple layers of abstraction too low to succinctly ping down the concept in question. Haskell brings (or rather is) a very rich language suited specifically for accurately describing the elements involved. That's why 1) the concept of a Monad is visible/cleanly expressible in the first place, and 2) people use it to explain the concept, even when (like this blog post) not aiming at a Haskell (or Haskell learner) audience. Disclaimer: I'm just a lowly OOP programmer, not written a line of Lisp or Haskell in my life. Watching from the sidelines for now. [0]: https://en.wikipedia.org/wiki/Hermitian_adjoint https://en.wikipedia.org/wiki/Hermitian_adjoint [1]: https://en.wikipedia.org/wiki/Liskov_substitution_principle https://en.wikipedia.org/wiki/Liskov_substitution_principle
- _ph_ 5y agoSay you have a source of A, and a way of turning an A into a source of B. An operation that uses these two inputs to produce a source of B is a monad. Did you mean to write "Say you have a source of A, and a way of turning an A into a B. An operation that uses these two inputs to produce a source of B is a monad"? What exactly do you consider a "source"? And the way of turning an A into a B I would call a function. And combining the "source of A" with a function that converts A's into B's, a concationation or composition of functions, or a way of currying. And yes, I am fully aware, that you sometimes need to learn the vocabulary to have a minimum discussion. But considering I have a degree in math and CS, have learned at least 10 programming languages, especially Lisp with all of its contexts, I am highly suspicious about something that cannot expressed in plain language. But thanks, your explanation comes closest I have seen so far.
- samhh 5y agoYou have a container with `a` inside, let's call the container `m`. You have `m a`. You can provide a function with the type signature `a -> b`. With this we run the function underneath `m` and map `m a -> m b`. Concretely this might be with for example lists, where given a function `Int -> String` I can map `[Int] -> [String]`. What the functor abstraction gives you is a consistent, lawful way to define this phenomenon for virtually every type you'd ever want to "map". Likewise monads for "flat mapping". This explanation was 90% accurate. What's missing is that not every functor or monad is a "container", for example Haskell's `IO`, which rather represents an action of sorts to impurely get a value. But the intuition will build all the same if you play with it a bit. It's all in the type signatures.