Is it better to define Functor in terms of Applicative in terms of Monad, or vice versa?

前端 未结 5 476
南笙
南笙 2021-02-02 13:25

This is a general question, not tied to any one piece of code.

Say you have a type T a that can be given an instance of Monad. Since every mona

5条回答
  •  日久生厌
    2021-02-02 14:05

    I think you mis-understand how sub-classes work in Haskell. They aren't like OO sub-classes! Instead, a sub-class constraint, like

    class Applicative m => Monad m
    

    says "any type with a canonical Monad structure must also have a canonical Applicative structure". There are two basic reasons why you would place a constraint like that:

    • The sub-class structure induces a super-class structure.
    • The super-class structure is a natural subset of the sub-class structure.

    For example, consider:

    class Vector v where
        (.^) :: Double -> v -> v
        (+^) :: v -> v -> v
        negateV :: v -> v
    
    class Metric a where
        distance :: a -> a -> Double
    
    class (Vector v, Metric v) => Norm v where
        norm :: v -> Double
    

    The first super-class constraint on Norm arises because the concept of a normed space is really weak unless you also assume a vector space structure; the second arises because (given a vector space) a Norm induces a Metric, which you can prove by observing that

    instance Metric V where
        distance v0 v1 = norm (v0 .^ negateV v1)
    

    is a valid Metric instance for any V with a valid Vector instance and a valid norm function. We say that the norm induces a metric. See http://en.wikipedia.org/wiki/Normed_vector_space#Topological_structure .

    The Functor and Applicative super-classes on Monad are like Metric, not like Vector: the return and >>= functions from Monad induce Functor and Applicative structures:

    • fmap: can be defined as fmap f a = a >>= return . f, which was liftM in the Haskell 98 standard library.
    • pure: is the same operation as return; the two names is a legacy from when Applicative wasn't a super-class of Monad.
    • <*>: can be defined as af <*> ax = af >>= \ f -> ax >>= \ x -> return (f x), which was liftM2 ($) in the Haskell 98 standard library.
    • join: can be defined as join aa = aa >>= id.

    So it's perfectly sensible, mathematically, to define the Functor and Applicative operations in terms of Monad.

提交回复
热议问题