Interfaces in Haskell

Interfaces are a way to define a set of functions that a type must implement. In Haskell, we can achieve similar functionality using typeclasses.

{-# LANGUAGE InstanceSigs #-}

module Geometry where

import Text.Printf (printf)

-- Here's a basic typeclass for geometric shapes.
class Shape a where
    area :: a -> Double
    perim :: a -> Double

-- For our example we'll implement this typeclass on
-- Rectangle and Circle types.
data Rectangle = Rectangle Double Double
data Circle = Circle Double

-- To implement a typeclass in Haskell, we use the 'instance' keyword.
-- Here we implement Shape for Rectangle.
instance Shape Rectangle where
    area :: Rectangle -> Double
    area (Rectangle width height) = width * height

    perim :: Rectangle -> Double
    perim (Rectangle width height) = 2 * width + 2 * height

-- The implementation for Circle.
instance Shape Circle where
    area :: Circle -> Double
    area (Circle radius) = pi * radius * radius

    perim :: Circle -> Double
    perim (Circle radius) = 2 * pi * radius

-- If a function takes a Shape constraint, then we can call
-- methods that are in the Shape typeclass. Here's a
-- generic 'measure' function taking advantage of this
-- to work on any Shape.
measure :: Shape a => a -> IO ()
measure shape = do
    print shape
    printf "Area: %.2f\n" (area shape)
    printf "Perimeter: %.2f\n" (perim shape)

-- We need to define how to print our shapes
instance Show Rectangle where
    show (Rectangle w h) = printf "Rectangle %.2f %.2f" w h

instance Show Circle where
    show (Circle r) = printf "Circle %.2f" r

main :: IO ()
main = do
    let r = Rectangle 3 4
    let c = Circle 5

    -- The Rectangle and Circle types both
    -- implement the Shape typeclass so we can use
    -- instances of these types as arguments to measure.
    measure r
    measure c

To run this program, save it as Geometry.hs and use ghc to compile it:

$ ghc Geometry.hs
$ ./Geometry
Rectangle 3.00 4.00
Area: 12.00
Perimeter: 14.00
Circle 5.00
Area: 78.54
Perimeter: 31.42

In this Haskell version, we use a typeclass Shape to define the interface for geometric shapes. The Rectangle and Circle types then implement this typeclass. The measure function can work with any type that implements the Shape typeclass.

This demonstrates how Haskell’s typeclasses can be used to achieve similar functionality to interfaces in other languages, allowing for polymorphic behavior while maintaining type safety.