Skip to content

Commit fc22050

Browse files
authored
[Chapter 3] Get rid of flip (#446)
1 parent bf8426b commit fc22050

File tree

1 file changed

+49
-46
lines changed

1 file changed

+49
-46
lines changed

text/chapter3.md

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ The source code for this chapter is contained in the file `src/Data/AddressBook.
1818

1919
Here, we import several modules:
2020

21+
- The `Prelude` module, which contains a small set of standard definitions and functions. It re-exports many foundational modules from the `purescript-prelude` library.
2122
- The `Control.Plus` module, which defines the `empty` value.
2223
- 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.
2324
- The `Data.Maybe` module, which defines data types and functions for working with optional values.
2425

25-
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.
26+
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.
2627

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

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

105-
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:
106-
107-
```text
108-
> import Prelude
109-
> :type flip
110-
forall a b c. (a -> b -> c) -> b -> a -> c
111-
112-
> :type const
113-
forall a b. a -> b -> a
114-
```
115-
116-
Functions can be defined at the top-level of a file by specifying arguments before the equals sign:
106+
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:
117107

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

139-
## Quantified Types
140-
141-
In the previous section, we saw the types of some functions defined in the Prelude. For example, the `flip` function had the following type:
142-
143-
```text
144-
> :type flip
145-
forall a b c. (a -> b -> c) -> b -> a -> c
146-
```
147-
148-
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.
149-
150-
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
151-
152-
```text
153-
(Int -> String -> String) -> String -> Int -> String
154-
```
155-
156-
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:
157-
158-
```text
159-
> flip (\n s -> show n <> s) "Ten" 10
160-
161-
"10Ten"
162-
```
163-
164-
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:
165-
166-
```text
167-
> flip (\n s -> show n <> s) 10 "Ten"
168-
169-
Could not match type Int with type String
170-
```
171-
172129
## Notes On Indentation
173130

174131
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.
@@ -293,6 +250,52 @@ Type
293250

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

253+
## Quantified Types
254+
255+
For illustration purposes, let's define a primitive function that takes any two arguments and returns the first one:
256+
257+
```text
258+
> :paste
259+
… constantlyFirst :: forall a b. a -> b -> a
260+
… constantlyFirst = \a b -> a
261+
… ^D
262+
```
263+
264+
> Note that if you use `:type` to ask about the type of `constantlyFirst`, it will be more verbose:
265+
>
266+
> ```text
267+
> : type constantlyFirst
268+
> forall (a :: Type) (b :: Type). a -> b -> a
269+
> ```
270+
>
271+
> The type signature contains additional kind information, which explicitly notes that `a` and `b` should be concrete types.
272+
273+
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.
274+
275+
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
276+
277+
```text
278+
Int -> String -> Int
279+
```
280+
281+
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:
282+
283+
```text
284+
> constantlyFirst 3 "ignored"
285+
286+
3
287+
```
288+
289+
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`):
290+
291+
```text
292+
:type constantlyFirst true "ignored"
293+
Boolean
294+
295+
:type constantlyFirst "keep" 3
296+
String
297+
```
298+
296299
## Displaying Address Book Entries
297300

298301
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:

0 commit comments

Comments
 (0)