Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

"abstraction over type constructors" isn't very meaningful without more context anyway, but they're probably referring to something like the following:

non-abstracted:

    map :: (a -> b) -> List a -> List b
abstracted:

    map :: Functor f => (a -> b) -> f a -> f b
"List" is a type constructor (it takes a type and returns a type), but we can write a "map" function that works over more types than just List - for example, Maps and Options and so on (aka "Functors" in Haskell parlance). We've "abstracted (the function map) over the type constructor (of the data structure being mapped over)".

To answer your more general question, if you just learn functional programming on a language with a powerful type system (Haskell is probably the most germane example) you will learn at least some of these terms. Most of them turn out not to be very deep, just hard to explain (for reasons unclear to those who understand them), but still very useful.



> We've "abstracted (the function map) over the type constructor (of the data structure being mapped over)".

Then why didn't they just call those types "Mappables"?


I think this is a great question because it tends to come up a lot.

What do you call the following common operations?

  - 1 + 0
  - 1 * 1
  - "string" ++ ""
  - [1, 2, 3] ++ []
As far as I know there is no term for this grouping of operations outside of functional programming languages which use category theory.

We call it a "monoid" based on the following precise definition:

> In abstract algebra, a branch of mathematics, a monoid is an algebraic structure with a single associative binary operation and an identity element[1].

I used the "identity element" specifically in my examples above since they tend to be a good way to grasp what is going on.

It turns out a "functor" has more properties than just being "mappable", which is why we like using the more precise term in our literature. However, it's still a decent intuition if you aren't familiar with the concept.

For example, in the parent comment the 'f' in the second line of code shows that it is some kind of structure that adheres to a Functor, and also infers that this structure can also be mapped over. This is a nice property because without caring about the implementation, we can still do functor-specific operations over abstract structures.

[1] https://en.wikipedia.org/wiki/Monoid


"binary operators with an identity value"


the binary operation should also be associative (e.g. subtraction is no good)


concat?


I can't think of any way for 1 * 1 to be concatenation.

I think the point GP was making is that a monoid has something to do with a function f that takes two arguments a and b where there is a single value for b such that f(a, special_value) == a. I think.

As someone who doesn't really understand FP concepts I would probably call those functions "functions that can sensibly be used in a call to array.reduce"


It doesn't need to have a perfect metaphor for all possible cases, just something you can picture in an instant: 'behaves like a concating variable length box sequences'. It's a mnemonic / learning aid, not a formal spec. But I can stretch it :)

+: concat marbles sequence

* : concat prime factors sequence

++: concat box sequence

For * , it can also be reduced to + via logarithms. I just don't have a good metaphor for '+ over reals' this morning.


“append”* is the name chosen for the binary operator in the Haskell standard library’s monoid abstraction and “concat” seems like the same genre, so I would expect people would be fine with the intuition for “concat” as well.

Given that this is a thread on functional jargon, it might be interesting to note list metaphors as being useful for thinking about monoid might derive from lists being free monoids (in many contexts). This means that all functions from a collection elements to a monoid can be thought of as functions from that collection into a list with the appropriate type of elements and then a fold (also called a reduction) over that list. This knowledge can be super useful for thinking about program structure e.g. conceptually mapreduce is a general tool for large-scale distributed computation over monoids.

*it’s actually called “mappend”[0], short for monoid append, but I think the point still stands (and there is, in fact, a function called “mconcat”[1] but folds of a list of monoidal values using “mappend” to combine them.)

[0] http://hackage.haskell.org/package/base-4.14.0.0/docs/Data-M...

[1] http://hackage.haskell.org/package/base-4.14.0.0/docs/Data-M...


> I just don't have a good metaphor for '+ over reals' this morning.

Skimming through my thesaurus, I found a word for it: "Totalize".


> "functions that can sensibly be used in a call to array.reduce"

You can use any function you want in a fold in Haskell. You're conflating two typeclasses, Monoids and Foldables, and restricting yourself to the function known in Haskell as foldMap.


You've definitely got the right intuition.

"associative": (a + b) + c == a + (b + c)

"binary": f a b == a `f` b == a + b where f is addition

"identity element": the "empty" value which when paired with a second value, returns the second value as is


> As someone who doesn't really understand FP concepts I would probably call those functions "functions that can sensibly be used in a call to array.reduce"

So reduceables?


That implies that they can be reduced. Maybe "reductors"?

That said, I am on the "name abstractions after the math" side of things. It makes it much clearer what guarantees I have when working with the interface, on either side of it.


That would probably have been clearer to newbies, but they already had a complete terminology ready to go from category theory and it's not hard to remember "Functor ~ Mappable". Plus, "obvious" names break down once you start building up hierarchies of these properties. One of the reasons people have a hard time communicating the (simple) ideas behind other algebraic objects like Applicatives, Monads, etc. is because it's hard to come up with short, self-descriptive names for them. The search for such names has resulted in several famously bad analogies, such as "a Monad is like a Burrito".


Because names don’t carry meaning, they’re pointers: https://www.parsonsmatt.org/2019/08/30/why_functor_doesnt_ma...

“Functor,” points to a specific concept in Haskell and a slightly different one in Category Theory but otherwise it is fairly unambiguous given enough context. The concept not only refers to the type and the associated “map” operation but also the axioms of identity and composition and their properties.

“Mappable,” is a very common name people pick in these discussions but it doesn’t clarify the meaning any more than calling it “Rose.” It may in fact cause more harm than good if a name like Mappable exists in more contexts. There are plenty of objects one can apply a map operation to that are not valid Functors.


Well, Functor is a bit of a misnomer; it really should be called TypeEndofunctor. The short form was really adopted as a mischievous pun on the use of "functor" in the OOP community.


I don't think TypeEndofunctor conveys any additional information when discussing a Haskell typeclass.

> The short form was really adopted as a mischievous pun on the use of "functor" in the OOP community.

Citation needed.


I should note that naming things with mischievous puns certainly wasn't beyond early Haskellers - that's the origin of `return` as a name for part of the Monad interface (since quasi-deprecated in favor of `pure`).

I just have never heard that allegation about `functor`, which seems to have been taken directly from mathematics that predate any notion of function object. It's possible that OO programmers and the mathematicians both borrowed it from the same source (it seems to have originated in linguistics).


> Because names don’t carry meaning, they’re pointers:

That's been debated in philosophy for over 150 years, and there are many alternative theories.

I think a better point is that technical names don't matter because their formal meaning may not correspond with any word, and if there is an everyday word, it's probably slightly but importantly different.


To be fair, the term "map" comes from math [0], and so at the time these functions were created, there weren't other good naming choices. Mappable and Functor are just about as opaque as each other if you don't know what mapping is.

Though now that FP concepts are mainstream, I think there is a good case to offer some friendlier, more familiar names:

Functor -> Mappable

Applicative -> Pairable

Monad -> Thenable

[0]: https://softwareengineering.stackexchange.com/questions/2033...


Giving descriptive names just harms intuition building in the long run.

I've been writing Haskell for over 5 years and to this day when I see <$>, <*>, >>= in my code I don't substitute English words for them.


Was about to complain you can't google them, but I tried it and it worked. Huh. I guess you can google symbols now, even traditionally escapey-ones. News to me.

mentalModel.update().

The query `python @` fails pretty hard though.


For Haskell stuff, you can go one better and use Hoogle: https://hoogle.haskell.org/?hoogle=%28%3C%24%3E%29&scope=set...


I tend to just query the repl when I don't know a symbol.

    :info (>=>)


> Giving descriptive names just harms intuition building in the long run.

Citation needed


(In my experience)


Like seriously isn't it obvious that I'm stating my opinion? And that the citation is my personal professional Haskell experience? We're talking about intuition building here it's not like I'm gonna be able to Debate You with Hard Facts -__-


Yes it's clear that you're stating your opinion. I asked for supporting evidence because I'm not persuaded by your opinion since I have the opposite opinion.


Well then I'll add:

Calling Functor "Mappable" and Monad "Thenable" doesn't really add much to understanding.

The best advice I ever got was that a Functor is `f` with a function `fmap :: (a -> b) -> f a -> f b` that follows its laws. Same goes for Monad. If it has the type signature & follows the laws, it's a Monad. That's the definition. No need for a cute analogy-oriented name like FlatMap-able or Then-able.

Once you do that, you realize that the way to understand these things is to play type tetris with highly-generic type signatures. You stop needing English/real-world analogies to understand them and instead use the type system to understand the world (the reverse of using "nice" names)

It works really well but it is a steep hill to climb. It helps to talk to others who have climbed it, and it helps to just grind on a project and use Monads without being an expert. You can go a long way just knowing how `do`, `traverse`/`mapM`, etc work and not having big Monad intuition.


> Citation needed

Citation needed.


All I see here is weakening the descriptive power of those terms by replacing them with more common ones. It may look easier but I think it’s probably better not to carry in baggage from other languages that doesn’t quite fit.


Because the concept is category-theoretic in nature and they wanted to foreground that.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: