Restricted Data Types

With some spare boredom I had this morning, I was skimming the section on functors in RWH. A little ways down they introduce the type:

data Eq a => Bar a = Bar a
instance Functor Bar where
    fmap f (Bar a) = Bar (f a)

And point out how the constraint does not allow a valid functor instance. But what if it did?

What I’m getting at is that nobody ever uses constraints on data definitions like that, because they’re basically useless (AFAIK, they just impose the constraint on each constructor and nothing more). Perhaps they could work in this way: the mention of the type Bar a implies the constraint Eq a. Thus:

fmap :: (a -> b) -> Bar a -> Bar b

The caller already provides the dictionaries Eq a and Eq b for you, because the types “Bar a” and “Bar b” come from his environment. I’m not sure what I mean by environment there.

The time you would be required to provide a dictionary would be if you used a Bar in the body of a function without mentioning it in the type signature.

If this makes sense (I’m not convinced it does in the least), it might be a nice way to solve the class restriction problem.

3 Comments

  1. Ryan Ingram
    Posted November 20, 2008 at 10:43 pm | Permalink

    Hmm, I’m not sure this works.

    Consider this:

    fcompose :: Functor f => (a -> b) -> (b -> c) -> f a -> f c
    fcompose a2b b2c f = fmap b2c (fmap a2b f)

    broken :: Bar Int -> Bar Int
    broken = fcompose (+) ($ 1)

    Nowhere in the environment do you see a Bar (Int -> Int), and it’s impossible to construct one as there’s no Eq instance at that type. But inside the internals of fcompose you do need to construct a Bar (Int -> Int)!

  2. Posted November 20, 2008 at 11:30 pm | Permalink

    With GADT syntax this wart was fixed, and restricted data constructors can indeed include a dictionary:

    data Bar a where
    Bar :: Eq a => a -> Bar a

    This still doesn’t allow you to write the Functor instance, since there is no Eq b.

  3. Luke
    Posted November 21, 2008 at 7:07 pm | Permalink

    Ryan: good catch. Well, it was a good idea before we found out it was nonsense. :-)

Post a Comment

Your email is never shared.