6

Let's say I want to define a tree like this:

{-# LANGUAGE DatatypeContexts #-}
class Node a where
  getContent :: (Num a) => a

data (Node a) => Tree a = Leaf a
                        | Branch a (Tree a) (Tree a)

-XDatatypeContexts is deprecated now. Is it possible to do something similar without it?

Jake
  • 154
  • 9

1 Answers1

13

Are you sure datatype contexts actually did what you think it did? It was deprecated because it was basically useless and widely considered a misfeature, since all it did was force you to add extra constraints without providing any guarantees about types beyond what you'd have had without it.

The replacement, such as it is, that actually does something useful, is GADT syntax. The equivalent of your type would look like this:

data Tree a where
    Leaf :: (Node a) => a -> Tree a
    Branch :: (Node a) => a -> Tree a -> Tree a -> Tree a

In this case, you need the Node constraint when creating a Tree value, but when pattern matching on a Tree value you also get an automatic guarantee that a Node instance exists, making the instance available without even needing it in the type of the function receiving Tree a as an argument.

mb21
  • 34,845
  • 8
  • 116
  • 142
C. A. McCann
  • 76,893
  • 19
  • 209
  • 302
  • Thank you very much! Though I think you mean Branch :: (Node a) => a -> Tree a -> Tree a – Jake Dec 15 '12 at 02:43
  • @Jake: No--it works just like a function type signature, so the last `Tree a` is the resulting data type. `a -> Tree a -> Tree a` would only have one sub-tree. Compare the type of the `Branch` constructor you have currently. – C. A. McCann Dec 15 '12 at 02:45
  • 2
    For what it's worth, you don't need GADT syntax for this. You can also write `data Tree a = Node a => Leaf a | Node a => Branch a (Tree a) (Tree a)`. – shachaf Dec 15 '12 at 06:36
  • 3
    Also, to Jake: What cmccann said would work, but are you completely sure it's what you want? The usual approach is to put constraints on functions that use `Tree`, rather than on the constructor -- e.g. `foo :: Node a => Tree a -> ...` -- and it has some important advantages over this one. Is there a reason it doesn't work for you in this case? – shachaf Dec 15 '12 at 06:39
  • @shachaf: To talk at someone, talk @ them. This will put a notification in their inbox, as this comment self-demonstrates. – C. A. McCann Dec 15 '12 at 16:14