Defining different data constructors for a type, and then defining functions using pattern matching over them resembles ad-hoc polymorphism in other languages a lot:
data Shape = Circle Float | Rectangle Float Float
area :: Shape -> Float
area (Circle r) = pi * r^2
area (Rectangle a b) = a*b
Using type classes you could do
class Shape s where
area :: s -> Float
data Circle = Circle Float
instance Shape Circle where
area (Circle r) = pi * r^2
data Rectangle = Rectangle Float Float
instance Shape Rectangle where
area (Rectangle a b) = a*b
One advantage of the second that I see is that it can be extended without touching existing declarations, in particular it may be your only option. Are there other reasons to prefer one over the other?
To make the 2nd approach work, you have to know the type
sat compile time while with the 1st approach you can match runtime valuesDifference between Type Class and Algebraic data types
Scala: difference between a typeclass and an ADT?
Type classes vs algebraic data types?