Code Whisperer
Code Whisperer

Reputation: 23662

PureScript - What is a newtype?

The PureScript handbook defines an exercise as follows:

Define a Show instance for Point. Match the same output as the showPoint function from the previous chapter. Note: Point is now a newtype (instead of a type synonym), which allows us to customize how to show it. Otherwise, we'd be stuck with the default Show instance for records. (https://book.purescript.org/chapter6.html)

However, no information about what a newtype is is provided.

What is a newtype? What is it for? Why does it work here, but not type?

Upvotes: 1

Views: 710

Answers (1)

Saravanan M
Saravanan M

Reputation: 129

Newtype is just a wrapper around one(or more) type. We usually use it to expose a predefined or already available type as a new type.

There are lot of useful things we can do with newtype, one of them is specified by the author in the chapter you've shared above.

When you specify

type Point = 
  { x :: Number
  , y :: Number
  }

You can't actually define your own type class instances(e.g show instance) as Point is just a type synonym for Record type which is predefined in Prim module of purescript.

So you wrap it with newtype, and make it a user defined type. Now you can derive whatever instance you want.

You can also use it to create more strict values. For example, you want to create a type name, when its size is less than 6, you want to emphasize a error. So what you do is,

type Name = Either String String

then you create a function,

type Name = Either String String 
createName' :: String -> Name 
createName' name 
 | (length name) >= 6 =   (Right name)
 | otherwise          =   (Left "Invalid Name")

you're happy now. But this doesn't restrict the other developer from doing something like

 myName :: Name
 myName = (Right "a")

So how you can let the Name to be created only by the function?

  1. By Only importing the function.
  2. By not importing the Name

The problem is you can't do 2nd step, as Name is just a type synonymn.

name :: Name is same as name :: Either String String

so you wrap the Either String String with a newtype

 newtype StrictName = MkName (Either String String)
 createName :: String -> StrictName 
 createName name 
    |  (length name) >= 6 =  MkName (Right name)
    |  otherwise          =  MkName (Left "Invalid Name")

now you only import the function and the StrictName(without its construtor) e.g

module Data.MyTypes.Name
(StrictName,createName)

Now there's no other way to create a StrictName value without using the createName function. (this is also doable with ADT types, but I prefer newtype)

Newtype are also used to handle orphan instances and many more useful things.

Note : Newtype adds runtimes overhead as theres one more wrapper around the original type.

Upvotes: 3

Related Questions