Skip to content

Commit

Permalink
[Chapter 3] Get rid of flip (#446)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zelenya authored Jul 17, 2023
1 parent bf8426b commit fc22050
Showing 1 changed file with 49 additions and 46 deletions.
95 changes: 49 additions & 46 deletions text/chapter3.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ The source code for this chapter is contained in the file `src/Data/AddressBook.

Here, we import several modules:

- The `Prelude` module, which contains a small set of standard definitions and functions. It re-exports many foundational modules from the `purescript-prelude` library.
- The `Control.Plus` module, which defines the `empty` value.
- The `Data.List` module, provided by the `lists` package, which can be installed using Spago. It contains a few functions that we will need for working with linked lists.
- The `Data.Maybe` module, which defines data types and functions for working with optional values.

Notice that the imports for these modules are listed explicitly in parentheses. This is generally a good practice, as it helps to avoid conflicting imports.
Notice that the imports for these modules are listed explicitly in parentheses (except for `Prelude`, which is typically imported as an open import). This is generally a good practice, as it helps to avoid conflicting imports.

Assuming you have cloned the book's source code repository, the project for this chapter can be built using Spago, with the following commands:

Expand Down Expand Up @@ -102,18 +103,7 @@ Fields of records can be accessed using a dot, followed by the label of the fiel
["Functional Programming","JavaScript"]
```

PureScript's functions correspond to JavaScript's functions. The PureScript standard libraries provide plenty of examples of functions, and we will see more in this chapter:

```text
> import Prelude
> :type flip
forall a b c. (a -> b -> c) -> b -> a -> c
> :type const
forall a b. a -> b -> a
```

Functions can be defined at the top-level of a file by specifying arguments before the equals sign:
PureScript's functions correspond to JavaScript's functions. Functions can be defined at the top-level of a file by specifying arguments before the equals sign:

```haskell
add :: Int -> Int -> Int
Expand All @@ -136,39 +126,6 @@ Having defined this function in PSCi, we can _apply_ it to its arguments by sepa
30
```

## Quantified Types

In the previous section, we saw the types of some functions defined in the Prelude. For example, the `flip` function had the following type:

```text
> :type flip
forall a b c. (a -> b -> c) -> b -> a -> c
```

The keyword `forall` here indicates that `flip` has a _universally quantified type_. It means we can substitute any types for `a`, `b`, and `c`, and `flip` will work with those types.

For example, we might choose the type `a` to be `Int`, `b` to be `String`, and `c` to be `String`. In that case, we could _specialize_ the type of `flip` to

```text
(Int -> String -> String) -> String -> Int -> String
```

We don't have to indicate in code that we want to specialize a quantified type – it happens automatically. For example, we can use `flip` as if it had this type already:

```text
> flip (\n s -> show n <> s) "Ten" 10
"10Ten"
```

While we can choose any types for `a`, `b`, and `c`, we have to be consistent. The type of function passed to `flip` had to be consistent with the types of the other arguments. That is why we passed the string `"Ten"` as the second argument and the number `10` as the third. It would not work if the arguments were reversed:

```text
> flip (\n s -> show n <> s) 10 "Ten"
Could not match type Int with type String
```

## Notes On Indentation

PureScript code is _indentation-sensitive_, just like Haskell, but unlike JavaScript. This means that the whitespace in your code is not meaningless, but rather is used to group regions of code, just like curly braces in C-like languages.
Expand Down Expand Up @@ -293,6 +250,52 @@ Type

PureScript's _kind system_ supports other interesting kinds, which we will see later in the book.

## Quantified Types

For illustration purposes, let's define a primitive function that takes any two arguments and returns the first one:

```text
> :paste
… constantlyFirst :: forall a b. a -> b -> a
… constantlyFirst = \a b -> a
… ^D
```

> Note that if you use `:type` to ask about the type of `constantlyFirst`, it will be more verbose:
>
> ```text
> : type constantlyFirst
> forall (a :: Type) (b :: Type). a -> b -> a
> ```
>
> The type signature contains additional kind information, which explicitly notes that `a` and `b` should be concrete types.
The keyword `forall` indicates that `constantlyFirst` has a _universally quantified type_. It means we can substitute any types for `a` and `b``constantlyFirst` will work with these types.

For example, we might choose the type `a` to be `Int` and `b``String`. In that case, we can _specialize_ the type of `constantlyFirst` to

```text
Int -> String -> Int
```

We don't have to indicate in code that we want to specialize a quantified type – it happens automatically. For example, we can use `constantlyFirst` as if it had this type already:

```text
> constantlyFirst 3 "ignored"
3
```

While we can choose any types for `a` and `b`, the return type of `constantlyFirst` has to be the same as the type of the first argument (because both of them are "tied" to the same `a`):

```text
:type constantlyFirst true "ignored"
Boolean
:type constantlyFirst "keep" 3
String
```

## Displaying Address Book Entries

Let's write our first function, which will render an address book entry as a string. We start by giving the function a type. This is optional, but good practice, since it acts as a form of documentation. In fact, the PureScript compiler will give a warning if a top-level declaration does not contain a type annotation. A type declaration separates the name of a function from its type with the `::` symbol:
Expand Down

0 comments on commit fc22050

Please sign in to comment.