Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: restrict "a" to certain types?

I have a tree intended to contain a tuple at each node:

-- Should be initialized with `a' as a tuple of (Int, Int) or (Float, Float)
data MMTree a = Empty | Node a (MMTree a) (MMTree a) deriving Show

Is there any way to restrict a so that MMTree can only be initialized with specific types; namely, (Int, Int) or (Float, Float) rather than any old type?

like image 362
Govind Parmar Avatar asked Feb 11 '26 14:02

Govind Parmar


1 Answers

Yes. You can use generalized algebraic datatypes (GADTs, http://en.wikibooks.org/wiki/Haskell/GADT), which exactly do what you need (type of result can depend on used constructor). As a simple solution, you can make a constructor for each possible node type:

{-# LANGUAGE GADTs #-}

data MMTree a where
  Empty :: MMTree a
  NodeI :: (Int, Int) -> MMTree (Int, Int) -> MMTree (Int, Int) -> MMTree (Int, Int)
  NodeF :: (Float, Float) -> MMTree (Float, Float) -> MMTree (Float, Float) -> MMTree (Float, Float)

However, this solution isn't very good (because you'll need to add more constructors if later you'll want to use the same tree type for other elements). So, DataKinds and TypeFamilies to the rescue:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}

data TreeType
  = TInt
  | TFloat

type family Elem (t :: TreeType) where
  Elem TInt = (Int, Int)
  Elem TFloat = (Float, Float)

data MMTree (t :: TreeType) where
  Empty :: MMTree a
  Node :: Elem a -> MMTree a -> MMTree a -> MMTree a

test1 :: MMTree TInt
test1 = Node (1, 1) Empty Empty

test2 :: MMTree TFloat
test2 = Node (2.0, 3.0) Empty Empty

This is the solution if you really would like to restrict used types in data declaration. However, I would like to suggest an easier solution: just leave your tree definition as is, and if you would like to process a tree where nodes are expected to contain tuples of numeric values, just write functions with type signature like that:

someFun :: (Num a) => MMTree (a, a) -> r
like image 108
AndrewShulaev Avatar answered Feb 13 '26 18:02

AndrewShulaev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!