# PureScript by example: Chapter Pattern Matching: Exercise: doubleScaleAndCenter

Hi, this is a solution for the Line case:

``````doubleScaleAndCenter line@(Line (Point s) (Point e)) =
Line
(Point { x: (s.x - cx) * 2.0, y: (s.y - cy) * 2.0 })
(Point { x: (e.x - cx) * 2.0, y: (e.y - cy) * 2.0 })
where
c = getCenter line
cx = getX c
cy = getY c
``````

If I use `c` directly, it does not work:

``````doubleScaleAndCenter line@(Line (Point s) (Point e)) =
Line
(Point { x: (s.x - c.x) * 2.0, y: (s.y - c.y) * 2.0 })
(Point { x: (e.x - c.x) * 2.0, y: (e.y - c.y) * 2.0 })
where
c = getCenter line
``````

I get

``````  Could not match type

{ x :: Number
| t0
}

with type

Point
``````

But `getX (Point p) = p.x`, why can’t they be substituted?

2 Likes

This is a great question that will likely help lots of other beginners. Thanks for posting.

The error you’re encountering is because the record is wrapped in a `Point` type constructor, and you’re trying to access a field without unwrapping it first. The `(Point p)` in `getX` unwraps `Point` and stores the inner record in `p`.

There are pros and cons to wrapping records in another type constructor. One of the cons is that unwrapping is a bit tedious. Here’s the version without wrapping:

``````-- Not wrapped (notice `type` is used instead of `data`)
type Point =
{ x :: Number
, y :: Number
}

-- You probably wouldn't even write a function for this. Just use .x instead.
getX :: Point -> Number
getX p = p.x
``````

The original for reference:

``````-- Wrapped (notice the additional `Point` constructor)
data Point = Point
{ x :: Number
, y :: Number
}

getX :: Point -> Number
getX (Point p) = p.x
``````

For other readers following along, here’s the relevant section in the text:

1 Like

I realized the reference solution for `centerShape` is not as clean as it could be, so here’s a PR to fix that. https://github.com/purescript-contrib/purescript-book/pull/253

Also wanted to briefly re-summarize some of the different ways to represent a `Point` record and motivations for each.

Type synonym:

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

The most convenient option. Start with this, unless you know you need one of the following options.

Newtype:

``````newtype Point = Point
{ x :: Number
, y :: Number
}
``````

Provides some additional type safety and allows you to override default behaviors. For example, if you wanted a customized way to `show` points that’s different than records (this will make more sense in the type classes chapter).

``````data Point = Point
{ x :: Number
, y :: Number
}
``````

I actually don’t see any reason for doing this versus `newtype`. It offers nothing beyond what’s covered above for `newtype`. It also loses some of the nice `wrap`/`unwrap` derived conveniences (not discussed here).

So I’m wondering if this section of the book should be modified to eliminate the impractical `data Point` and replace with either:

1. `newtype Point`.
2. `type Point` in Ch5. Then in Ch6, follow-up on the type class motivations for `newtype` (teased in last line of newtype section) and ask for a `Show` instance for `newtype Point` in the first exercise. Edit: This is shaping up to be a nice simplification (PR).
2 Likes

(slight correction for any newcomers looking to copy-paste this code)
You have

``````newtype Point =
{ x :: Number
, y :: Number
}
``````

and it would have to be

``````newtype Point = Point
{ x :: Number
, y :: Number
}
``````

For any newcomers reading this, the `newtype` keyword is a drop-in replacement for the `data` keyword that offers some performance benefits and `wrap`/`unwrap` goodies that @milesfrain mentions, but is only allowed when you wrap just one thing. So

``````data MyConcreteType = MyConcreteConstructor MyConcreteThing
data MyGenericType genericThing = MyGenericConstructor genericThing
``````

can be replaced by

``````newtype MyConcreteType = MyConcreteConstructor MyConcreteThing
newtype MyGenericType genericThing = MyGenericConstructor genericThing
``````

But you could not use newtype for things like

``````data ZeroThings = EmptyConstructor
data TwoThings = MyConstructor Thing1 Thing2
data TwoConstructors
= Constructor1 Thing1
| Constructor2 Thing2
``````

Good find. I must have assumed the compiler is good enough to catch errors I make in forum posts too. Edited the original.

1 Like

The one place I would use `data` for a data type with a single constructor is if I knew I would be adding more constructors later on. That way the compiler will stop me from using things like `derive newtype instance` or `wrap`/`unwrap` which only work with newtypes, saving me from having to redo them later. You’ll probably have to update lots of the places the data type is used when adding constructors anyway though, so perhaps it doesn’t make a huge difference.

2 Likes