Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An example of a type with kind * -> * which cannot be an instance of Functor

I'm very much a Haskell novice, so apologies if the answer is obvious, but I'm working through the Typeclassopedia in an effort to better understand categories. When doing the exercises for the section on Functors, I came across this problem:

Give an example of a type of kind * -> * which cannot be made an instance of Functor (without using undefined).

My first thought was to define some kind of infinitely recursing definition of fmap, but wouldn't that essentially be the same as if undefined was used in the definition?

If someone could explain the answer it would be greatly appreciated.

Thanks!

Source of original exercise here, section 3: http://www.haskell.org/haskellwiki/Typeclassopedia#Introduction

like image 765
JS. Avatar asked Apr 20 '13 08:04

JS.


People also ask

What is a functor in Haskell?

Functor in Haskell is a kind of functional representation of different Types which can be mapped over. It is a high level concept of implementing polymorphism. According to Haskell developers, all the Types such as List, Map, Tree, etc. are the instance of the Haskell Functor.

How does fmap work Haskell?

Here's how it works. fmap takes an a -> b function and an f a data type ( a wrapped in any context f ). The function is applied to what's inside the context, and a value of type b wrapped in f is returned. The value can change, but the context remains the same.

What is pure in Haskell?

From HaskellWiki. A function is called pure if it corresponds to a function in the mathematical sense: it associates each possible input value with an output value, and does nothing else.


2 Answers

A simple example is

data K a = K (a -> Int)

Here's what ghci tells us is we try to automatically derive a Functor instance for K:

Prelude> :set -XDeriveFunctor
Prelude> data K a = K (a -> Int)
Prelude> :k K
K :: * -> *
Prelude> data K a = K (a -> Int) deriving Functor

<interactive>:14:34:
    Can't make a derived instance of `Functor K':
      Constructor `K' must not use the type variable in a function argument
    In the data type declaration for `K'

The problem is that the standard Functor class actually represents covariant functors (fmap lifts its argument to f a -> f b), but there is no way you can compose a -> b and a -> Int to get a function of type b -> Int (see Ramon's answer). However, it's possible to define a type class for contravariant functors:

class Contravariant f where
    contramap :: (a -> b) -> f b -> f a 

and make K an instance of it:

instance Contravariant K where
    contramap f (K g) = K (g . f)

For more on covariance/contravariance in Haskell, see here.

Edit: Here's also a nice comment on this topic from Chris Smith on Reddit.

like image 82
Mikhail Glushenkov Avatar answered Oct 04 '22 23:10

Mikhail Glushenkov


To expand on my (short) comment and on Mikhail's answer:

Given (-> Int), you'd expect fmap to look as such:

(a -> Int) -> (a -> b) -> (b -> Int)

or:

(a -> Int) -> (a -> b) -> b -> Int

It is easy to prove that from the three arguments (a -> Int), (a -> b), b there is no possible way to reach Int (without undefined), thus from (a -> Int), (a -> b) there is no way to reach (b -> Int). Conclusion: no Functor instance exists for (-> Int).

like image 6
Ramon Snir Avatar answered Oct 04 '22 22:10

Ramon Snir