Search code examples
purescript

PureScript - How to Add or Subtract NewTypes


Consider this intuitive example, where one attempts to use the (+) operator on two NewTypes derived from Number:

module Main where

import Prelude (Unit, (+))
import Effect (Effect)
import Effect.Console (logShow)

newtype Balance = Balance Number

a :: Balance
a = Balance 7.18

b :: Balance
b = Balance 16.50

c :: Balance
c = a + b

main :: Effect Unit
main = do
  logShow c

However, attempting this operation produces the following error:

No type class instance was found for
  
    Data.Semiring.Semiring Balance
  

while applying a function add
  of type Semiring t0 => t0 -> t0 -> t0
  to argument a
while inferring the type of add a
in value declaration c

where t0 is an unknown type

So, in essense, the question is

How do you operate on newtypes as though they were the type they were derived from?

So ideally this solution would also work when concatenating two values of a new type based on string, or comparing two values of a new type based on boolean, etc.


Solution

  • newtypes do not inherit the typeclass implementations of the underlying type. You either have to implement it manually, or if it's supported, derive the instance. In this case, PureScript supports deriving addition (Data.Semiring):

    newtype Balance = Balance Number
    
    derive newtype instance Semiring Balance
    

    Full code (you can copy paste it into https://try.purescript.org/ to try):

    module Main where
    
    import Prelude (Unit, (+))
    import Data.Semiring (class Semiring)
    import Data.Show (class Show)
    import Effect (Effect)
    import Effect.Console (logShow)
    
    newtype Balance = Balance Number
    
    derive newtype instance Semiring Balance
    derive newtype instance Show Balance
    
    main :: Effect Unit
    main = do
      logShow ((Balance 7.18) + (Balance 16.50))
    

    Output:

    23.68