[Haskell-cafe] fundeps => type family
Tad Doxsee
tad.doxsee at gmail.com
Sun Apr 3 22:00:03 CEST 2011
Hi All,
Last week I asked a question with the subject "object oriented
technique". I got a lot very helpful answers and I thank all who
contributed. At the end of my question, I alluded to some problems
that I was having with what I wanted to do next, which was to add
additional polymorphism. I figured out a solution, which is:
-------------------------------------------------
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
data Rectangle a = MkRectangle { rx, ry, rw, rh :: a }
deriving (Eq, Show)
drawRect :: Show a => Rectangle a -> String
drawRect r = "Rect (" ++ show (rx r) ++ ", " ++ show (ry r) ++ ") -- "
++ show (rw r) ++ " x " ++ show (rh r)
data Circle a = MkCircle {cx, cy, cr :: a}
deriving (Eq, Show)
drawCirc :: Show a => Circle a -> String
drawCirc c = "Circ (" ++ show (cx c) ++ ", " ++ show (cy c)++ ") -- "
++ show (cr c)
r1 = MkRectangle 0 0 3 2
r2 = MkRectangle 1 1 4 5
c1 = MkCircle 0 0 5
c2 = MkCircle 2 0 7
class ShapeC a s | s -> a where
draw :: s -> String
copyTo :: s -> a -> a -> s
{-
-- GADT version
data ShapeD a where
MkShapeD :: ShapeC a s => s -> ShapeD a
-}
-- Existential Quantification version
data ShapeD a = forall s . ShapeC a s => MkShapeD s
instance ShapeC a (ShapeD a) where
draw (MkShapeD s) = draw s
copyTo (MkShapeD s) x y = MkShapeD (copyTo s x y)
mkShape :: ShapeC a s => s -> ShapeD a
mkShape s = MkShapeD s
instance Show a => ShapeC a (Rectangle a) where
draw = drawRect
copyTo (MkRectangle _ _ rw rh) x y = MkRectangle x y rw rh
instance Show a => ShapeC a (Circle a) where
draw = drawCirc
copyTo (MkCircle _ _ r) x y = MkCircle x y r
r1s = MkShapeD r1
r2s = MkShapeD r2
c1s = MkShapeD c1
c2s = MkShapeD c2
shapes1 = [r1s, r2s, c1s, c2s]
drawing1 = map draw shapes1
shapes2 = map mkShape rs ++ map mkShape cs
drawing2 = map draw shapes2
-- copy the shapes to the origin then draw them
shapes3 = map (\s -> copyTo s 0 0) shapes2
drawing3 = map draw shapes3
-------------------------------------------------
The main difference with my previous version is that the above
is polymorphic in the type for the origin and dimensions.
(I used a Double previously.)
Also, the above version uses existential quantification instead
of GADTs, only because some said that that method is more
"standard".
I had to use functional dependencies in the defintion of class
ShapeC to get it to compile and run.
Ed Yang's excellent post
(http://blog.ezyang.com/2011/03/type-tech-tree)
says that type families are equivalent to multiparameter type classes
+ functional dependencies, so I tried to rewrite the above using
type families, but I got stuck. Also the GHC documentaton
(http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/type-families.html#id636192)
says that
"Equality constraints ... enable a simple translation of programs
using functional dependencies into programs using family
synonyms instead.
So I tried:
class (T s ~ a) => ShapeC a s where
type T s :: *
draw :: s -> String
copyTo :: s -> T s -> T s -> s
but got a compile error:
Alas, GHC 7.0 still cannot handle equality superclasses: T s ~ a
So my question is, how does one convert the above code to use type
families instead of functional dependencies? Is one technique
preferable over another?
Thanks,
Tad
More information about the Haskell-Cafe
mailing list