0

I'm reading Purely Functional Data Structres and trying to solve exercises they give in haskell.

I've defined Tree in a standard way data Tree a = Empty | Node a (Tree a) (Tree a) I'd like to define Set as Tree where nodes are instance of Ord. Is there a way to express this in Haskell? Something like type Set = Tree Ord or I deemed to reimplement tree every time I want express some data structure as tree?

user1685095
  • 5,787
  • 9
  • 51
  • 100

2 Answers2

3

Do you intend to use the tree as a binary search tree (BST)? For that to work, you need all operations to preserve the strong BST property: for each Node constructor in the BST, all Nodes in the left subtree contain elements less than the one in the current Node, all Nodes in the right subtree contain elements greater.

You absolutely need to preserve that property. Once it's no longer true, all further BST operations lose correctness guarantees. This conclusion has consequences. You can't expose the constructors of the type. You can't expose operations to work on it that don't preserve the BST property.

So every operation that operates on a set needs to have access to the Ord instance for the type constrained in the node. (Well, other than a couple special cases like checking if a set is empty or creating a singleton set, which never have to deal with the order of children.)

At that point, what exactly can you share about the tree type with other uses? You can't share operations. You can't use the constructors. That leaves, well.. nothing useful. You could share the name of the type with no ways to do much of anything with it.

So, no.. You can't share a binary search tree data type with other uses that just seek an arbitrary binary tree. Attempting to do so just results in a broken BST.

Carl
  • 26,500
  • 4
  • 65
  • 86
  • Hmm, well how about sharing traversable and other stuff? There must be something common right? They both trees, you know. I'm not intended to do anything with it. It's just an exercise. – user1685095 Jun 09 '17 at 14:05
  • 1
    @user1685095 You can't even really write a `Traversable` instance for a BST. `runIdentity . traverse (pure . negate)`, for instance. Yeah, that's just a glorified `fmap negate`, but that just shows that the problem comes at a lower level than `Traversable`. You can even go further and ask if a structural `Eq` instance is what you want for a BST - wouldn't you rather have `Eq` test that they contain the same elements, rather than requiring identical structure as well? – Carl Jun 09 '17 at 14:37
  • Thanks for you answer! – user1685095 Jun 09 '17 at 16:33
2

This is exactly what Data.Set module from containers library does:

http://hackage.haskell.org/package/containers-0.5.10.2/docs/src/Data-Set-Internal.html#Set

You can try to read it's implementation. type Set = Tree Ord won't compile if you're not using some exotic language extensions. But you're probably don't want to use them and more interested in functions like:

insert :: Ord a => a -> Tree a -> Tree a
find   :: Ord a => a -> Tree a -> Maybe a
delete :: Ord a => a -> Tree a -> Tree a

This is how type classes meant to be used.

Shersh
  • 9,019
  • 3
  • 33
  • 61
  • I've already read it. They reimplemented `Tree`. You haven't answered my question though. Can `Set type is a Tree with ordered elements` be expressed in Haskell. Maybe not with type alias, but without reimplementing tree. Yes or no? And why yes or no. – user1685095 Jun 09 '17 at 14:02
  • No, because "Set type is a Tree with ordered elements" is not a true statement. It is possible to represent a Set as a Tree with ordered elements, but something like your imagined `type Set a = Ord a => Tree a` isn't sufficient. As Carl mentions above, you need further guarantees on the structure of the tree. In particular, you need invariants that can't be enforced (or even described) by Haskell's type system. – Rein Henrichs Jun 09 '17 at 16:30