haskelltypestype-aliastype-synonyms

Getting Haskell to Distinguish Type Synonyms


I like the idea of Haskell type synonyms, because they allow for distinguishing between abstract datatypes that share underlying representations. Unfortunately, when I write a program like

data Vector a = Vec a a

-- Some definitions here about (+) and (*) for Vector ...

type Position = Vector Float
type Velocity = Vector Float
type Time = Float

step :: Position -> Velocity -> Time -> Position
step p v dt = p + v*dt

p :: Position
p = Vec 0.0 0.0

v :: Velocity
v = Vec 1.0 1.0

p' = step v p 0.01

This is perfectly valid Haskell code, despite v and p being in the wrong spots. I would like to strengthen the distinction between type synonyms, such that they still share underlying representation, but are not accepted as each other in function application. Is this possible?


Solution

  • You could make Vector a phantom type as follows:

    data Vector t a = Vec a a
    
    data Pos
    data Vel
    
    type Position = Vector Pos Float
    type Velocity = Vector Vel Float
    

    Now, you can define instances of Position and Velocity like you'd normally do:

    p :: Position
    p = Vec 0.0 0.0
    
    v :: Velocity
    v = Vec 1.0 1.0
    

    However, it won't allow you to use them interchangeably:

    type Time = Float
    
    step :: Position -> Velocity -> Time -> Position
    step p v dt = p + v*dt -- you might have to change this definition
    
    p' = step v p 0.01 -- won't compile
    

    You can also make things more precise by using DataKinds and KindSignatures:

    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE KindSignatures #-}
    
    data VectorType = Pos | Vel
    
    data Vector (t :: VectorType) a = Vec a a
    
    type Position = Vector Pos Float
    type Velocity = Vector Vel Float
    

    Hope that helps.