Make Data Type of Kind * -> * That's Not a Functor

前端 未结 2 750
Happy的楠姐
Happy的楠姐 2021-02-02 18:02

Brent Yorgey\'s Typeclassopedia gives the following exercise:

Give an example of a type of kind * -> * which cannot be made an instance

2条回答
  •  时光取名叫无心
    2021-02-02 18:29

    A type t of kind * -> * can be made an instance of Functor if and only if it is possible to implement a law-abiding instance of the Functor class for it. So that means you have to implement the Functor class, and your fmap has to obey the Functor laws:

    fmap id x == x
    fmap f (fmap g x) == fmap (f . g) x
    

    So basically, to solve this, you have to name some type of your choice and prove that there's no lawful implementation of fmap for it.

    Let's start with a non-example, to set the tone. (->) :: * -> * -> * is the function type constructor, as seen in function types like String -> Int :: *. In Haskell, you can partially apply type constructors, so you can have types like (->) r :: * -> *. This type is a Functor:

    instance Functor ((->) r) where
        fmap f g = f . g
    

    Intuitively, the Functor instance here allows you to apply f :: a -> b to the return value of a function g :: r -> a "before" (so to speak) you apply g to some x :: r. So for example, if this is the function that returns the length of its argument:

    length :: [a] -> Int
    

    ...then this is the function that returns twice the length of its argument:

    twiceTheLength :: [a] -> Int
    twiceTheLength = fmap (*2) length
    

    Useful fact: the Reader monad is just a newtype for (->):

    newtype Reader r a = Reader { runReader :: r -> a }
    
    instance Functor (Reader r) where
        fmap f (Reader g) = Reader (f . g)
    
    instance Applicative (Reader r) where
        pure a = Reader (const a)
        Reader f <*> Reader a = Reader $ \r -> f r (a r)
    
    instance Monad (Reader r) where
        return = pure
        Reader f >>= g = Reader $ \r -> runReader g (f r) r
    

    Now that we have that non-example out of the way, here's a type that can't be made into a Functor:

    type Redaer a r = Redaer { runRedaer :: r -> a } 
    
    -- Not gonna work!
    instance Functor (Redaer a) where
        fmap f (Redaer g) = ...
    

    Yep, all I did is spell the name backwards, and more importantly, flip the order of the type parameters. I'll let you try and figure out why this type can't be made an instance of Functor.

提交回复
热议问题