DEV Community

Discussion on: Functors, Monads and better functions

Collapse
 
totally_chase profile image
Phantz

I'm going to log some of my thoughts while reading this post, hopefully this may serve as constructive feedback, as well as notes to other readers-

Category explanation

The explanation on what a category itself is, is spot on. Incredible job there, it unifies both the formal definition and the haskell implementation (Control.Category) extremely well.

To add to your definition, I'd suggest readers to draw an intuitive analogy to sets. Most people are familiar with sets and set theory, not so much category theory. But really, a set is very similar to a category. In fact, a category can be thought of as a "set" equipped with some morphism on its elements. Don't get scared by the word morphism! It's just a fancy word for a function. Well, a pure function, of course :)

Functors explanation

I think the definition you used for functors is quite vague in an informal way. Don't get me wrong, there's nothing wrong with informality when explaining these topics - but it seems like you tried to combine the functors in fp, and the functors in category theory into one definition. A functor in haskell is really a concrete (and constrained) application of the abstract functor concept from category theory. Meanwhile, an actual functor, is "a mapping between categories".

I personally would suggest preferring the concrete functor definition over the abstract one. To say, "a functor is simply a computational context that can be mapped over" feels both intuitive and correct, in the context of haskell (and therefore in pretty much all fp langs).

Monads "compose"

This wording- "What's special about them is that they are composable.", regarding monads, is....problematic. This isn't really anyone's fault. It just so happens that "compose" is used ambiguously in many places in these contexts. Monads don't compose!. That is their weakness.

I understand what you meant, you're talking about the composition of functions returning monads - the Kleisli arrow. But perhaps it'd be better to say- err, monads chain..? It's a bit of a difficult analogy to be made here. Since skipping applicative functors has been, and still is, a historical mistake. The idea of chaining functions in a higher order world (functor world) - really bears well with applicative functors. Monads are also a pattern for chaining operations - but the monadic operation is binding, whereas an applicative functor operation is just applying. The key distinction is that monad allows dynamically choosing what computation (functor) is executed next, depending on the previous result. Applicatives may only choose statically. See: difference between applicatives and monads.

Monads allow the higher order world and the regular world to seamlessly interface. This is clear in the type signature of bind/>>=. Look at the function it takes as argument- a -> m b. a is a regular value, m b is a higher order value, it's a computational context! A functor! A higher order value! We've just let the user meddle the 2 worlds together. <*> and fmap don't let the user do this.

This essentially gives you a get-out-of-jail-free card to essentially design a completely imperative API.

Of course, this comes with major drawbacks - hence why many consider the focus on monads before applicatives.... a historical mistake. Monads don't compose. Dynamically choosing effects is expensive. In many cases, an applicative can do everything you need - just much more efficiently. A true unsung hero, it saddens me to not see this article mention applicatives.

|> in Haskell

Actually, haskell does have a |> in the standard :). It's & from Data.Function. It's just a flipped version of $. Nothing special. Though >>= does not combine andThen and &. >>= is andThen (but flipped). The exact haskell alternative is =<< They're the same thing. In fact, you could write-

parseFloat someString & (=<<) (divide 7)
-- Same as parseFloat someString |> andThen (divide 7)
-- Whoa, look at that similarity! They're the exact same!
Enter fullscreen mode Exit fullscreen mode

Which, of course, can be simplified to-

parseFloat someString >>= divide 7
Enter fullscreen mode Exit fullscreen mode

Covariant mapping of functions

The idea you discussed in "Function signatures" is very nice. I think that particular intuition is also a great door opener to contravariance. Contravariant functors, that is. Reverse all the arrows!

Which functor is not a monad?

+1 for the recommendation about "Try to think of a functor that isn't a monad". This is a neat little exercise once you have decent grasp of the covariant functor hierarchy (covariant is the default one in haskell, and therefore other fp langs).

Some hints to aid in your journey, dear readers- Remember, a covariant functor won't be a monad if and only if the functor can proceed through bind without actually containing value. You need the a to actually feed into a -> m b! Think of sum types! Notice how Maybe a is a monad because Nothing is not allowed to pass through bind. If Nothing was allowed, what would you pass to the a -> m b function? nothing!

Good stuff all around. Such a refresher to see something braver than "how to make a landing page with react". Keep it up!

Collapse
 
drbearhands profile image
DrBearhands • Edited

Fair points.

I'm curious how you came upon this article. I posted it almost 3 years ago.

EDIT: just checked out the sources you posted for applicatives. Thanks for those. Real eye-openers. Academic literature made them sound almost like some obscure technicality.

Collapse
 
totally_chase profile image
Phantz

Oh whoa I didn't even notice the date. Whoops, sorry for necroing. A friend of mine posted this and cited it as "an interesting dev.to article". I frankly just assumed it was new :P.

That's pretty hilarious though. My friend must've been searching for articles on FP concepts on dev.to and happened to stumble upon your post.

Thread Thread
 
drbearhands profile image
DrBearhands

No problem at all. Hey, I learned something new! I was just curious how that happens.