News for hackers. Stuff that matters.
Re:Monads are monoids in the category of endofunctors by dwohnitmok on Thursday September 09, 2021 @08:32PM (#28476421)
> a functor is just a pure unary function?

No, although a pure unary function could be viewed as a functor, the other direction doesn't hold.

The common FP definition of a functor is anything that supports a notion of `map` (subject to the restriction that `map`ping the identity function does nothing, this is why a Functor is slightly more than just a Mappable). This is not a unary function although map takes a unary function as an argument.

The more general mathematical definition is a mapping between categories. Categories are sufficiently general that you can view almost anything as a category, which is why a unary function can be thought of as a functor (because a functor can be a mapping between categories that happen to be sets).

But a functor is both more general than a unary function and, in a certain sense, preserves more structure than a function, since it must preserve the structure of the underlying categories whereas functions generally only care about sets.

Re:Monads are monoids in the category of endofunctors by tantalor on Thursday September 09, 2021 @09:15PM (#28476685)
> why a Functor is slightly more than just a Mappable

Explain that again?

Re:Monads are monoids in the category of endofunctors by opnitro on Thursday September 09, 2021 @09:24PM (#28476742)
A Mappable would be anything that has a `map` function. A `Functor` is a something that has a `map` function _AND_ obeys the rule that calling `map` with the identity function produces the same result.

ie: say I have some value `f` that is a functor. If I call `map identity f` I should always get back `f`. The mere existence of a `map` function doesn't imply this law holds.

The identity function always returns it's argument unmodified. (identity x = x)

(Now, in Haskell the type system does not encode that law, but not following it would be breaking the interface.)

If this explanation doesn't make sense or you need more examples I'm happy to expand

EDIT: Both me and grandparent forgot another law for functors. They also need to preserve composition.

fmap (f . g) == fmap f . fmap g

In english, if I combine the functions f and g and map them, it should be the same as if I first map g and then map f

Re:Monads are monoids in the category of endofunctors by dwohnitmok on Thursday September 09, 2021 @09:37PM (#28476831)
> They also need to preserve composition.

I didn't state this because this generally comes for free, assuming no shenanigans such as runtime type reflection/type-casing (but in that case all laws go out the window). In particular in Haskell (which is what I assume you're coming from given fmap and your ML-ish syntax) this is a superfluous law. If a type constructor's `fmap` obeys the identity law, it must obey the composition law.

Re:Monads are monoids in the category of endofunctors by opnitro on Friday September 10, 2021 @12:15AM (#28477764)
Yes that seems right, sorry.
Re:Monads are monoids in the category of endofunctors by Shish2k on Friday September 10, 2021 @05:26AM (#28479343)
> A Mappable would be anything that has a `map` function. A `Functor` is a something that has a `map` function _AND_ obeys the rule that calling `map` with the identity function produces the same result.

This sentence just taught me more about functional programming terminology than 4 years of university and 20 years of casual blog-post reading :O

Re:Monads are monoids in the category of endofunctors by OJFord on Friday September 10, 2021 @06:20AM (#28479630)
> They also need to preserve composition.

> fmap (f . g) == fmap f . fmap g

Can you give an example where that doesn't follow from `map identity f == f`? Assuming of course `f` .. is what I think is called 'pure'? i.e. is deterministic on its input arguments.

Re:Monads are monoids in the category of endofunctors by tantalor on Friday September 10, 2021 @07:34AM (#28480081)
What is a good example (not contrived) of a mappable non-functor?
Re:Monads are monoids in the category of endofunctors by dwohnitmok on Friday September 10, 2021 @12:53PM (#28484209)
Great question! There's a minority of them, but the ones I've run into the wild all usually boil down to having some internal book-keeping that is either triggered by function calls or can affect a function call.

For example, caches whose eviction calculation is triggered by function invocation aren't functors, even if you can map over the elements in the cache (since just calling any function on the cache can cause certain elements to be evicted). That's a bit of a weird one because caches also usually have some time-dependent behavior (which in general makes notions of things like equality a bit hard to pin down and so moots a lot of laws), but you can also have caches with eviction policies that are not based on time strictly, but rather deterministic heuristics that use the number of function calls as an input to the heuristic.

Another example is certain tree-based data structures that use function calls to rebalance themselves in a way where the rebalancing causes publicly observable changes. Again there just calling map by itself can trigger a rebalancing, regardless of whether identity is passed or not.

Another example is stuff like variants of `Iterator` where just iterating over something creates changes or function calls are logged.

FWIW all these cases of a mappable non-functor can be changed into a mappable functor, simply by "suspending" calling the function until you actually ask for a value (so the `map` call does nothing other than just squirrel the function away somewhere). So often the idea of a mappable non-functor isn't useful so much for truly distinguishing a functor from a non-functor, as it is for pointing out how you should implement `map` in a way that "makes sense."

Re:Monads are monoids in the category of endofunctors by opnitro on Friday September 10, 2021 @12:03PM (#28483449)
To be honest with you, you're right in that you usually get that one without trying. Most of the things we think of as mappable obey the identity rules.
Re:Monads are monoids in the category of endofunctors by tantalor on Friday September 10, 2021 @12:54PM (#28484225)
I think the confusion is calling anything that doesn't "obey the rules" a map function just because it is named "map".

For example, ruby's hash "map" returns an array instead of hash. That's not really a map, is it?

Making this useless distinction between "things with map function" and "functors" serves no purpose. It should be "things with real/fake map functions".

The name of the function does not matter!

Re:Monads are monoids in the category of endofunctors by opnitro on Friday September 10, 2021 @11:54PM (#28489308)
Sure, the name doesn't matter. The type does though. `Functor f => a -> b -> f a -> f b` And it most type systems the law can't easily be captured in the type system.
Re:Monads are monoids in the category of endofunctors by dwohnitmok on Thursday September 09, 2021 @09:27PM (#28476762)
In theory you could have something like

  interface Mappable<A> {
    // Interfaces don't quite cut it here, because you want 
    // `map` to return a specific implementation of 
    // Mappable, not a general Mappable, but we'll let that 
    // slide for the purposes of exposition
    map<B>(f: A => B): Mappable<B>
  }

  class MyWeirdMappable<A>(val myCounter: Int, val myValue: A) implements Mappable<A> {

    // Notice the return type is MyWeirdMappable not 
    // Mappable, as mentioned earlier
    map<B>(f: A => B): MyWeirdMappable<B> {
      if (myCounter == 0) {
        return this
      } else {
        return MyWeirdMappable(myCounter + 1, f(myValue))
      }
    }
  }
Although this fulfills the contract of `Mappable`, it's not a `Functor`, because `map(identity)` doesn't always return the same (or equivalent) `MyWeirdMappable`.