Further to TomMD's answer, you can use Agda to the same effect. Although it doesn't have typeclasses, you get most of the functionality (apart from dynamic dispatch) from records.
record Direction (a : Set) : Set₁ where
field
turnLeft : a → a
turnRight : a → a
commLaw : ∀ x → turnLeft (turnRight x) ≡ turnRight (turnLeft x)
I thought I'd edit the post and answer the question of why you can't do this in Haskell.
In Haskell (+ extensions), you can represent equivalence as used in the Agda code above.
{-# LANGUAGE GADTs, KindSignatures, TypeOperators #-}
data (:=:) a :: * -> * where
Refl :: a :=: a
This represents theorems about two types being equal. E.g. a
is equivalent to b
is a :=: b
.
Where we they are equivalent, we can use the constructor Refl
. Using this, we can perform functions on the proofs (values) of the theorems (types).
-- symmetry
sym :: a :=: b -> b :=: a
sym Refl = Refl
-- transitivity
trans :: a :=: b -> b :=: c -> a :=: c
trans Refl Refl = Refl
These are all type-correct, and therefore true. However this;
wrong :: a :=: b
wrong = Refl
is clearly wrong and does indeed fails on type checking.
However, through all this, the barrier between values and types has not been broken. Values, value-level functions and proofs still live on one side of the colon; types, type-level functions and theorems live on the other. Your turnLeft
and turnRight
are value-level functions and therefore cannot be involved in theorems.
Agda and Coq are dependently-typed languages, where the barrier does not exist or things are allowed to cross over. The Strathclyde Haskell Enhancement (SHE) is a preprocessor for Haskell code that can cheat some of the effects of DTP into Haskell. It does this by duplicating data from the value world in the type world. I don't think it handles duplicating value-level functions yet and if it did, my hunch is this might be too complicated for it to handle.