Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add section on record puns and type synonyms for records #330

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 81 additions & 3 deletions language/Records.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,36 @@ Fields of records can be accessed using a dot, followed by the label of the fiel
["Functional Programming","JavaScript"]
```

Type synonyms for record types are created with the `type` keyword:

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

Comment on lines +23 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is covered later in this documentation, but I suppose it's information worth stating right away. Why not stick with the existing example in this section, though?

It is common to use type synonyms to for records via the type keyword:

type Author = { name :: String, interests :: Array String }

author :: Author
author = { name: "Phil", interests: ["Functional Programming", "JavaScript"] }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to define Point, since it's used in later examples.

## Kinds

`{ ... }` is just syntactic sugar for the `Record` type constructor, so `{ language :: String }` is the same as `Record ( language :: String )`.
`{ ... }` is syntactic sugar for the `Record` type constructor. This type constructor is parameterized by a row of types:

The Record type constructor is parameterized by a row of types. In kind notation, `Record` has kind `Row Type -> Type`. That is, it takes a row of types to a type.
```purescript
-- these types are equivalent
type Language = { language :: String }
type Language' = Record ( language :: String )
```

`( language :: String )` denotes a row of types (something of kind `Row Type`), so it can be passed to `Record` to construct a type, namely `Record ( language :: String )`.
A `Record` is constructed from a row type and represents a product type in which all fields in the row type are present. Using kind notation, `Record` has the kind `Row Type -> Type` -- that is, it takes a row of types and produces a type.

Because `( language :: String )` denotes a row of types (and therefore has the kind `Row Type`), it can be passed to the `Record` constructor or to the `{ ... }` syntax for `Record` to construct a type:

```purescript
type LanguageRow = ( language :: String ) -- has kind Row Type

-- these are equivalent
type Language = Record LanguageRow
type Language' = { | LanguageRow }
```

## Extending Records

Expand Down Expand Up @@ -79,6 +102,61 @@ A record update function can also be defined by using an `_` inplace of the reco
_ { fieldName = newValue }
```

## Record Puns
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this section, but there's some overlap with the language syntax documentation:
https://github.com/purescript/documentation/blob/837ec4ff3a956cdeda31997bf5f697ee738295b6/language/Syntax.md#additional-forms-with-records

I think we should merge that content into this file and then update the language syntax file to link here. It makes more sense for that content to be in this section and just a link be in that file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that file has good content and it could be used to inform what you've written here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's some overlap with the language syntax

I'm not seeing any "Record Pun" examples in Syntax.md, but I agree that there are duplicated themes across Records.md, Syntax,md, and Pattern-Matching.md.

Whether this should be reorganized seems like a bigger discussion. Maybe something to tackle as part of #344

So for now, I'm thinking we should hold-off on making changes across multiple files.


_Record puns_ enable concise code when record fields have the same name as other values. This feature is useful for constructing records and pattern matching.

### Constructing

```purs
origin :: Point
origin = { x, y }
-- origin = { x: x, y: y } -- Equivalent
where
x = 0.0
y = 0.0
```

### Pattern Matching

```purs
showPoint :: Point -> String
showPoint { x, y } = show x <> ", " <> show y
-- showPoint { x : x, y : y } = show x <> ", " <> show y -- Equivalent
```

### Not for Record Updates

Note that puns may not be used for record updates.

```purescript
setX :: Number -> Point -> Point
setX x point = point { x = x }
-- setX x point = point { x } -- Not allowed
```

## Further Record Operations

The [`record`](https://pursuit.purescript.org/packages/purescript-record) package enables additional record operations, such as `merge`, `union`, and efficient ways to create records (see [Record.Builder](https://pursuit.purescript.org/packages/purescript-record/docs/Record.Builder)).

Here's an example of using the `disjointUnion` function to add a `z` field to a `Point` record. The `to3d` function merges the original record `p` with another record `{ z }` created from this new `Number`:

```purescript
import Record (disjointUnion)

type Point3d =
{ x :: Number
, y :: Number
, z :: Number
}

to3d :: Point -> Number -> Point3d
to3d p z = disjointUnion p { z }

-- Equivalent to:
to3d p z = { x: p.x, y: p.y, z }
```

## Field Names

Symbols which are illegal value identifiers, such as title-cased identifiers or ones containing spaces, can be used to identify a field by enclosing it in double-quotes:
Expand Down