Interfaces in PureScript

module Main where

import Prelude
import Effect (Effect)
import Effect.Console (log)
import Math (pi)

-- Here's a basic interface for geometric shapes.
class Geometry a where
  area :: a -> Number
  perim :: a -> Number

-- For our example we'll implement this interface on
-- `Rect` and `Circle` types.
data Rect = Rect { width :: Number, height :: Number }
data Circle = Circle { radius :: Number }

-- To implement an interface in PureScript, we need to create
-- an instance of the typeclass for our types.
-- Here we implement `Geometry` for `Rect`.
instance geometryRect :: Geometry Rect where
  area (Rect r) = r.width * r.height
  perim (Rect r) = 2.0 * r.width + 2.0 * r.height

-- The implementation for `Circle`.
instance geometryCircle :: Geometry Circle where
  area (Circle c) = pi * c.radius * c.radius
  perim (Circle c) = 2.0 * pi * c.radius

-- If a function takes a typeclass constraint, then we can call
-- methods that are in the named typeclass. Here's a
-- generic `measure` function taking advantage of this
-- to work on any `Geometry`.
measure :: forall a. Geometry a => a -> Effect Unit
measure g = do
  log $ show g
  log $ show $ area g
  log $ show $ perim g

main :: Effect Unit
main = do
  let r = Rect { width: 3.0, height: 4.0 }
  let c = Circle { radius: 5.0 }

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

In PureScript, we use typeclasses to achieve a similar functionality to Go’s interfaces. The Geometry typeclass defines the methods area and perim, which are then implemented for the Rect and Circle types.

The measure function takes a type constraint Geometry a =>, which allows it to work with any type that implements the Geometry typeclass.

To run this program, you would typically compile it with the PureScript compiler and then run it with Node.js:

$ pulp build
$ node output/Main.js
(Rect { width: 3.0, height: 4.0 })
12.0
14.0
(Circle { radius: 5.0 })
78.53981633974483
31.41592653589793

This example demonstrates how PureScript uses typeclasses to achieve polymorphism, similar to how interfaces are used in other languages. The typeclass system in PureScript is more powerful and flexible than traditional interfaces, allowing for features like multiple parameter typeclasses and functional dependencies.