Reputation: 23662
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
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?
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