In Functional Programming, what is a functor?

后端 未结 17 579
孤独总比滥情好
孤独总比滥情好 2020-11-28 17:23

I\'ve come across the term \'Functor\' a few times while reading various articles on functional programming, but the authors typically assume the reader already understands

相关标签:
17条回答
  • 2020-11-28 17:37

    Not to contradict the previous theoretical or mathematical answers, but a Functor is also an Object (in an Object-Oriented programming language) that has only one method and is effectively used as a function.

    An example is the Runnable interface in Java, which has only one method: run.

    Consider this example, first in Javascript, which has first-class functions:

    [1, 2, 5, 10].map(function(x) { return x*x; });
    

    Output: [1, 4, 25, 100]

    The map method takes a function and returns a new array with each element being the result of the application of that function to the value at the same position in the original array.

    To do the same thing is Java, using a Functor, you would first need to define an interface, say:

    public interface IntMapFunction {
      public int f(int x);
    }
    

    Then, if you add a collection class which had a map function, you could do:

    myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });
    

    This uses an in-line subclass of IntMapFunction to create a Functor, which is the OO equivalent of the function from the earlier JavaScript example.

    Using Functors let you apply functional techniques in an OO language. Of course, some OO languages also have support for functions directly, so this isn't required.

    Reference: http://en.wikipedia.org/wiki/Function_object

    0 讨论(0)
  • 2020-11-28 17:38

    The word "functor" comes from category theory, which is a very general, very abstract branch of mathematics. It has been borrowed by designers of functional languages in at least two different ways.

    • In the ML family of languages, a functor is a module that takes one or more other modules as a parameter. It's considered an advanced feature, and most beginning programmers have difficulty with it.

      As an example of implementation and practical use, you could define your favorite form of balanced binary search tree once and for all as a functor, and it would take as a parameter a module that provides:

      • The type of key to be used in the binary tree

      • A total-ordering function on keys

      Once you've done this, you can use the same balanced binary tree implementation forever. (The type of value stored in the tree is usually left polymorphic—the tree doesn't need to look at values other than to copy them around, whereas the tree definitely needs to be able to compare keys, and it gets the comparison function from the functor's parameter.)

      Another application of ML functors is layered network protocols. The link is to a really terrific paper by the CMU Fox group; it shows how to use functors to build more complex protocol layers (like TCP) on type of simpler layers (like IP or even directly over Ethernet). Each layer is implemented as a functor that takes as a parameter the layer below it. The structure of the software actually reflects the way people think about the problem, as opposed to the layers existing only in the mind of the programmer. In 1994 when this work was published, it was a big deal.

      For a wild example of ML functors in action, you could see the paper ML Module Mania, which contains a publishable (i.e., scary) example of functors at work. For a brilliant, clear, pellucid explanation of the ML modules system (with comparisons to other kinds of modules), read the first few pages of Xavier Leroy's brilliant 1994 POPL paper Manifest Types, Modules, and Separate Compilation.

    • In Haskell, and in some related pure functional language, Functor is a type class. A type belongs to a type class (or more technically, the type "is an instance of" the type class) when the type provides certain operations with certain expected behavior. A type T can belong to class Functor if it has certain collection-like behavior:

      • The type T is parameterized over another type, which you should think of as the element type of the collection. The type of the full collection is then something like T Int, T String, T Bool, if you are containing integers, strings, or Booleans respectively. If the element type is unknown, it is written as a type parameter a, as in T a.

        Examples include lists (zero or more elements of type a), the Maybe type (zero or one elements of type a), sets of elements of type a, arrays of elements of type a, all kinds of search trees containing values of type a, and lots of others you can think of.

      • The other property that T has to satisfy is that if you have a function of type a -> b (a function on elements), then you have to be able to take that function and product a related function on collections. You do this with the operator fmap, which is shared by every type in the Functor type class. The operator is actually overloaded, so if you have a function even with type Int -> Bool, then

        fmap even
        

        is an overloaded function that can do many wonderful things:

        • Convert a list of integers to a list of Booleans

        • Convert a tree of integers to a tree of Booleans

        • Convert Nothing to Nothing and Just 7 to Just False

        In Haskell, this property is expressed by giving the type of fmap:

        fmap :: (Functor t) => (a -> b) -> t a -> t b
        

        where we now have a small t, which means "any type in the Functor class."

      To make a long story short, in Haskell a functor is a kind of collection for which if you are given a function on elements, fmap will give you back a function on collections. As you can imagine, this is an idea that can be widely reused, which is why it is blessed as part of Haskell's standard library.

    As usual, people continue to invent new, useful abstractions, and you may want to look into applicative functors, for which the best reference may be a paper called Applicative Programming with Effects by Conor McBride and Ross Paterson.

    0 讨论(0)
  • 2020-11-28 17:38

    "Functor is mapping of objects and morphisms that preserves composition and identity of a category."

    Lets define what is a category ?

    It's a bunch of objects!

    Draw a few dots (for now 2 dots, one is 'a' another is 'b') inside a circle and name that circle A(Category) for now.

    What does the category holds ?

    Composition between objects and Identity function for every object.

    So, we have to map the objects and preserve the composition after applying our Functor.

    Lets imagine 'A' is our category which has objects ['a', 'b'] and there exists a morphism a -> b

    Now, we have to define a functor which can map these objects and morphisms into another category 'B'.

    Lets say the functor is called 'Maybe'

    data Maybe a = Nothing | Just a
    

    So, The category 'B' looks like this.

    Please draw another circle but this time with 'Maybe a' and 'Maybe b' instead of 'a' and 'b'.

    Everything seems good and all the objects are mapped

    'a' became 'Maybe a' and 'b' became 'Maybe b'.

    But the problem is we have to map the morphism from 'a' to 'b' as well.

    That means morphism a -> b in 'A' should map to morphism 'Maybe a' -> 'Maybe b'

    morphism from a -> b is called f, then morphism from 'Maybe a' -> 'Maybe b' is called 'fmap f'

    Now lets see what function 'f' was doing in 'A' and see if we can replicate it in 'B'

    function definition of 'f' in 'A':

    f :: a -> b
    

    f takes a and returns b

    function definition of 'f' in 'B' :

    f :: Maybe a -> Maybe b
    

    f takes Maybe a and return Maybe b

    lets see how to use fmap to map the function 'f' from 'A' to function 'fmap f' in 'B'

    definition of fmap

    fmap :: (a -> b) -> (Maybe a -> Maybe b)
    fmap f Nothing = Nothing
    fmap f (Just x) = Just(f x)
    

    So, what are we doing here ?

    We are applying the function 'f' to 'x' which is of type 'a'. Special pattern matching of 'Nothing' comes from the definition of Functor Maybe.

    So, we mapped our objects [a, b] and morphisms [ f ] from category 'A' to category 'B'.

    Thats Functor!

    0 讨论(0)
  • 2020-11-28 17:38

    Functor is not specifically related to functional programming. It's just a "pointer" to a function or some kind of object, that can be called as it would be a function.

    0 讨论(0)
  • 2020-11-28 17:44

    In OCaml, it's a parameterised module.

    If you know C++, think of an OCaml functor as a template. C++ only has class templates, and functors work at the module scale.

    An example of functor is Map.Make; module StringMap = Map.Make (String);; builds a map module that works with String-keyed maps.

    You couldn't achieve something like StringMap with just polymorphism; you need to make some assumptions on the keys. The String module contains the operations (comparison, etc) on a totally ordered string type, and the functor will link against the operations the String module contains. You could do something similar with object-oriented programming, but you'd have method indirection overhead.

    0 讨论(0)
  • 2020-11-28 17:44

    You got quite a few good answers. I'll pitch in:

    A functor, in the mathematical sense, is a special kind of function on an algebra. It is a minimal function which maps an algebra to another algebra. "Minimality" is expressed by the functor laws.

    There are two ways to look at this. For example, lists are functors over some type. That is, given an algebra over a type 'a', you can generate a compatible algebra of lists containing things of type 'a'. (For example: the map that takes an element to a singleton list containing it: f(a) = [a]) Again, the notion of compatibility is expressed by the functor laws.

    On the other hand, given a functor f "over" a type a, (that is, f a is the result of applying the functor f to the algebra of type a), and function from g: a -> b, we can compute a new functor F = (fmap g) which maps f a to f b. In short, fmap is the part of F that maps "functor parts" to "functor parts", and g is the part of the function that maps "algebra parts" to "algebra parts". It takes a function, a functor, and once complete, it IS a functor too.

    It might seem that different languages are using different notions of functors, but they're not. They're merely using functors over different algebras. OCamls has an algebra of modules, and functors over that algebra let you attach new declarations to a module in a "compatible" way.

    A Haskell functor is NOT a type class. It is a data type with a free variable which satisfies the type class. If you're willing to dig into the guts of a datatype (with no free variables), you can reinterpret a data type as a functor over an underlying algebra. For example:

    data F = F Int

    is isomorphic to the class of Ints. So F, as a value constructor, is a function that maps Int to F Int, an equivalent algebra. It is a functor. On the other hand, you don't get fmap for free here. That's what pattern matching is for.

    Functors are good for "attaching" things to elements of algebras, in an algebraically compatible way.

    0 讨论(0)
提交回复
热议问题