7 ms·
I feel like these tutorials always fall apart when they start introducing Haskell syntax and say "That's Monad, simple as that!" class Functor f where fl
by avalys 5y ago
I feel like these tutorials always fall apart when they start introducing Haskell syntax and say "That's Monad, simple as that!"
class Functor f where
flip fmap :: f a -> (a -> b) -> f b
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
Sorry, that's not doing much for me! I am now going to look for a tutorial on Monads that's written in, say, Python, so at least I don't have to learn an abstract new language alongside the abstract new concept.
- staticassertion 5y agoI found this useful as a Rust dev: https://varkor.github.io/blog/2019/03/28/idiomatic-monads-in-rust.html https://varkor.github.io/blog/2019/03/28/idiomatic-monads-in... I agree with you entirely that the Haskell syntax is probably one of the biggest issues with monads being approachable.
- wyager 5y agoThis blog post is maybe 10% about monads and 90% dealing with why you can’t have them in rust (no HKTs). I hardly think that’s more approachable…
- staticassertion 5y agoIt was for me.
- aszen 5y agoIs that true though, you can't define a generic monadic interface yes but you can implement the same interface for your data types. That makes it less useful as the post says but still pretty powerful in some cases
- the_af 5y agoWhat's difficult about Haskell syntax? Or do you mean "it's an issue because it doesn't look like C, Java or Python?".
- toastal 5y agoIn many ways Haskell (and other languages in the ML family) are LISP with a lot less parentheses.
- the_af 5y agoIn which ways? I don't find lisp syntax confusing either.
- magicalhippo 5y agoFor me it is indeed the latter. I can glean a lot of interesting stuff from other languages as long as they look a bit familiar. Haskell I usually come to a dead stop pretty quickly. I've tried to read up on some Haskell basics, but the main issue is I don't have any real incentive to use Haskell, I have other hobbies that are more tempting, so I forget pretty quick. The Java-ish version of the Functor interface for instance was quite readable to me, ugly or not.
- wyager 5y ago> I am now going to look for a tutorial on Monads that's written in, say, Python It probably won’t be very helpful. The definition of a monad is 90% in the types. People use Haskell to talk about monads for two reasons: 1. Its type system is expressive enough to represent them (parametric polymorphism and higher-kinded types) 2. It’s one of a very small number of languages that doesn’t let users wiggle their way around needing some kind of principled effect system, so you really can’t get away without monads. Only in such an environment can the social pressure to take shortcuts be overcome, forcing people to structure their code carefully enough that the rich concept of monads isn’t reduced to a few occasionally used and probably incorrectly implemented corner cases like optional values and maybe futures.
- yoz-y 5y agoWait. Assuming one does not need or want to learn Haskell, what would then be a purpose of learning about monads? There seems to be a disproportionate amount of tutorials about monads. Not being able to provide sufficient amount of examples in other languages makes monads seem quite less useful. Maybe next article to write is “why should you learn about monads”.
- herbstein 5y agoThe point about Haskell is that it forces you to, or at least heavily nudges you to, understand monads and the rest of the typeclass hierarchy. However, you use the properties of monads all the time. The Stream APIs in JAVA and LINQ in C# are examples of abstractions built around Monads and their properties. The definition of a monad, as it relates to programming, emerges when you realize that an Option type, a Result/Either type, a List type, and a bunch of other non-container types all have the equivalent of a `flat_map` function. Write out a few mathematical rules for how a well-behaved implementation should compose and you have a Monad and its rules. This is why another approach to learning monads that isn't focused on the theory introduces it as a design pattern instead. I find this to be great for intuition but horrible for understanding personally, having used both approaches to teach people about Monads IRL.
- lmm 5y ago
- drdeca 5y agothe first one means that flip fmap is a function which, given an "f a", and a function from a to b, will produce an "f b". for example, if "f" is "list of" and a is "integer" and b is "string", then flip fmap would take as input a list of integer, and a function from integer to string, and produce a list of string. If you've done some topology: [or, maybe a is a particular topological space and b is another topological space, and f is "the fundamental group of", then given an element of the fundamental group of a, and a function from the topological space a to the topological space b, it will give you a corresponding element of the fundamental group of b.] a and b are both types of things, f takes in a type, and outputs another type. so, a and f a are both types (usually different types). the thing is that f doesn't just let you make a type from another type, it also lets you translate a function from the type a to the type b, to a function from the type f a to the type f b.
- mrspeaker 5y agoTo be fair, this particular article is titled 'Functors and Monads For People Who Have Read Too Many "Tutorials"'... after your tenth monad tutorial, you start getting good at reading types!
- the_af 5y ago> Sorry, that's not doing much for me! It's easy if you first learn about Haskell notation and type classes, which pretty much every online tutorial covers. What you quoted isn't arcane, you're just unfamiliar with it (just like my granma would find C-like syntax illegible: she just wouldn't know anything about it).
- 0xFF69B4 5y agoMonads and Functors aren't particularly exciting in Python because properties or contexts can be expressed with e.g. boolean flags and properties or contexts can be ignored when applying functions to unrelated parts of an object. # milk_cows :: Person -> Tired Person def milk_cows(person): ... person["tired"] = True return person # feed_pigs :: Person -> Tired Person def feed_pigs(person): ... person["tired"] = True return person # birthday :: Person -> Person def birthday(person): person["age"] += 1 return person # willy :: Person willy = {"age": 32, "tired": False} # fmap and >>= print(milk_cows(birthday(feed_pigs(willy)))) In Haskell there would be a 'Tired a' type with a Monad instance to express the tiredness property and a Functor instance to apply functions to it with no impact on or knowledge of tiredness, e.g. aging.
- shp0ngle 5y agoWell, that's Haskell for you. Haskell folks love arrows and one letter variable names. I don't know why, I guess it's the algebra background of most Haskell folks. When I wrote some things in Haskell, I tried to use full words for function names and variable names, but it felt I am the only one. People just love to name stuff `a` `b` `m` `f` `k`
- creata 5y agoThe one-letter variables are all type parameters, and pretty much every programming language uses one-letter variables for type parameters. And I can't think of a better syntax for "functions from a to b" than (a → b). In a Java-ish syntax it'd look like: interface Functor { <T, U> Self<U> fmap(Self<T>, Function<T, U>); } which is just torture. What would it look like in your ideal syntax?
- one_comment 5y agoGive the types useful names, like everything else. Recently I did a review for a new peer and was pleasantly surprised that they used proper names for generic arguments. At first I stumbled of course, because I wasn't used to generic arguments being longer than a few characters but I think it helped the readability a lot. interface Functor { <Source, Target> Self<Target> fmap(Self<Source>, Function<Source, Target>); } Same code, but you get an additional hint of what's going on.
- creata 5y agoAlright, that's fine, but the person I replied to was complaining that "Haskell folks love arrows and one letter variable names", and my point was that most programmers love one letter variable names in this context.
- contravariant 5y agoIt also doesn't help that that definition removes pretty much every aspect of what makes a monad a monad. It also deviates quite a bit from the mathematical definition. A definition like: bind f (x:xs) = f(x) would fit this type signature, but would very much not be a monad. What makes a monad a monad is that it is a functor (so a special parametrized type of sorts) with - a function to wrap a single value (wrap :: a -> M a) - a function that can flatten nested versions (flatten :: M M a -> M a) - such that wrapping twice and flattening is the same as wrapping once - such that when flattening a triply nested structure it doesn't matter which level you flatten first. And of course it also needs to satisfy the functor axioms, which are also frequently overlooked, though they're not too difficult they just mean that 'fmap' needs to play nice with identity functions and function composition. And Haskell in particular suffers quite a bit from the fact that currying is a first class concept, while in category theory this is reserved for a rather special class of categories. This means that using functors in combination with functions of multiple arguments suddenly requires you to think about how to evaluate a tree of functions on a tree of values, where in most other languages you'd end up with a tree of tuples at worst. Granted you can do more if you solve those problems, but it requires you to think about concepts that even category theorists consider pretty 'out there'.
- przemo_li 5y agoClosest but VERY BADLY BROKEN analogy to Monads is one of many Java standard interfaces. Would you agree that introducing particular interface is gonna show interface definition in question? What should follow (just like in Java) is few examples of actual implementations and how they fit into that interface.