質問

In category theory functor is a homomorphism between two categories. In Haskell, it's said that applicative functor allows us to apply functions "inside a functor". Could one translate that words "function inside a functor" back to mathematics or give some other insight? (I know that functor can be Maybe, [] etc. but still struggle to comprehend that notion.)

役に立ちましたか?

解決

My category theory is not strong at all (I started from the programming side of Haskell and have been recently trying to learn some of the category theory foundations of some of its concepts). But here's what I've got:

In Haskell, a functor is a type constructor, meaning it maps from general types to "types in the functor".

In category theory, a functor maps from the objects of one category to the objects of another category.

When applying category theory to Haskell, we imagine that we're working with the category Hask, the category of Haskell types.

So Haskell functors aren't general category theory functors; they all map from Hask to a sub-category of Hask (because the type f a for some functor f and arbitrary type a is still a Haskell type). For example the Maybe functor maps objects (types) in Hask to the category of types of the form Maybe a.

Functions are first-class in Haskell, so function types are perfectly ordinary types (and are objects of Hask) so functors also map function types to "function types in the functor". So the phrase "a function inside a functor" is a shorthand for a value in a type that results from applying a functor to a function type. e.g. Just (+1) is one particular value in the type Maybe (Int -> Int), which is the object (type) to which the Maybe functor maps the object Int -> Int.

So an "applicative functor" is a functor which has some extra rules, which are sufficient to take values which are functions in types which are objects of the functor's "destination" category, and apply those values to other values in types in the destination category.

Using Maybe again as an example, if we only knew it was a functor that gives us a correspondence between the objects Int -> Char and Maybe (Int -> Char), and between the objects Int and Maybe Int, and between the objects Char and Maybe Char. But while we have the ability to take a value in Int -> Char and a value in Int and produce a value in Char, Maybe being a functor doesn't guarantee that we have any ability to do some corresponding operation with a value in Maybe (Int -> Char) and a value in Maybe Int.

When we also know it's an applicative functor, then we do have an ability to take a value in Maybe (Int -> Char) and a value in Maybe Int and produce a value in Maybe Char, and this satisfies certain properties wrt the application of Int -> Char values to Int values.

As far as I know, applicative functors aren't terribly interesting from a pure category theory standpoint. Perhaps this is because category theory is concerned with relationships between objects, which correspond to types in Haskell, but from a programming perspective applicative functors are motivated by relationships between values in those types? (we want the values in the "function types" obtained by using the functor to still be able to be applied to things to do computation).

他のヒント

Translation Back to Math

In a closed monoidal category there is a notion of "exponent" which "internalizes" the morphism relation. You can then evaluate these exponents. That is, you have a way of saying (excuse my notion, Stackoverflow lacks mathjax)

eval : (a ~> b,a) -> b

as well as meta operations for currying and uncurrying.
An "applicative functor" maps exponents in an "applicable" way, F (a ~> b) can be combined with an F a to get an F b. This is because applicative functors are monoidal functors, so they have an operation (in the target category)

f a -> f b -> f (a,b)

which when you also fmap eval gives you ap from Haskell.

I doubt that was usefull,

The Haskell

The best way to understand an applicative functor is to look at the type

class Functor f => Applicative f where
  pure :: a -> f a
  <*>  :: f (a -> b) -> f a -> f b

the trivial example is

newtype Id a = Id a
instance Applicative Id where
  pure a = Id a
  Id f <*> Id a = Id (f $ a)

Id is also a Monad. In fact, all Monads are Applicative.

pure = return
mf <*> mx = do f <- mf
               x <- mx
               return (f x)

a more interesting example though is infinite sequences

data Seq a = Seq a (Seq a)
instance Applicative Seq where
  pure a = Seq a (pure a)
  (Seq f fs) <*> (Seq x xs) = Seq (f x) (fs <$> xs)

You can think of this as being equivalent to zipWith $ on lists. All Monads are Applicative, but I think the infinite sequence is fun because the corresponding monad instance is...non obvious (and rather slow). It will be left as an exercise to the reader (btw, I am steeling this example/exercise from something I remember reading that I think pigworker wrote on this site).

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top