7 ms·
> 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 de
by dwohnitmok 5y ago
> 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.
- tantalor 5y ago> why a Functor is slightly more than just a Mappable Explain that again?
- opnitro 5y agoA 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
- dwohnitmok 5y ago> 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.
- opnitro 5y agoYes that seems right, sorry.
- Shish2k 5y ago> 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
- OJFord 5y ago> 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.
- tantalor 5y agoWhat is a good example (not contrived) of a mappable non-functor?
- opnitro 5y agoTo 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.
- dwohnitmok 5y agoIn 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`.
- lupire 5y agoWell it depends how you define Mappable, but... Pythonish pseduocode: BadFunctor is a List (of generic type) with def badMap(function, stuff) : return [map(function, stuff) + map(function, stuff)] That's a Mappable, but not a Functor.