
On Sat, Jul 19, 2014 at 07:44:46PM -0300, Rafael Almeida wrote:
I was talking to friends about how could you make a Point type in haskell. It's intuitive to make a 2D point such as:
type Point2D = (Double, Double)
Using a list would be more general:
type Point = [Double]
now we have a nice, general add function
add = zipWith (+)
It's not so fun that we are able to do something like:
add [2,3] [5,7,11]
We have no type-safety that we can only operate on points with the same dimension.
How could we address this? Can we make a general function, yet retain the type safety?
A possible solution /without/ using Template Haskell is using phantom types for the various kind of |Point|s. Example: data Point a = Point [Int] deriving (Show) data Two -- data declaration sans constructors data Three crea2d :: Int -> Int -> Point Two crea2d a b = Point [a,b] crea3d :: Int -> Int -> Int -> Point Three crea3d a b c = Point [a,b,c] addPoints :: Point a -> Point a -> Point a addPoints (Point pa) (Point pb) = Point $ zipWith (+) pa pb So you are sure addPoints is will only type-check on two similarly constructed (i.e. same dimensions) |Point|s: ex2 = crea2d 1 2 -- make sure that "exSomething" is the only way to ex3 = crea3d 1 2 3 -- create Points (i.e. don't export Point(..)) works = addPoints ex2 ex2 stillworks = addPoints ex3 ex3 doesntwork = addPoints ex2 ex3 -- won't type-check Phantom types are a well known trick for "shifting" checks from run-time to compile-time.