PureScript by Example 3 章の前半を読む

この記事は [(bouzuya) PureScript Advent Calendar 2016](http://www.adventar.org/calendars/1494) の 7 日目です。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録です。

- ← 6 日目『 [PureScript by Example 2 章を読む - Qiita][2016-12-06] 』
- → 8 日目『 [PureScript by Example 3 章の後半を読む - Qiita][2016-12-08] 』

## 概要

昨日に続き [PureScript by Example][purescript-by-example] と [PureScript Language Guide][purescript-language-guide] を見ながら進めていきます。今日は [PureScript by Example の 3 章][purescript-by-example-3] の前半を読みます。

※注意事項: 英語と日本語訳では大きな差異があります。`0.10.x` に対応している英語の側で進めます。

- [PureScript by Example][purescript-by-example] 2016-12-05 時点で 0.10.x 向け
- [実例による PureScript][purescript-by-example-ja] 2016-12-05 時点で 0.7 向け
- [PureScript Language Guide][purescript-language-guide] 対象バージョン不明

## PureScript by Example 3.1

この章では、関数とレコードという PureScript の構成要素を、アドレス帳アプリケーションという例を通じて学べるようです。

## PureScript by Example 3.2

コードは https://github.com/paf31/purescript-book/tree/8ad7d2af75ad4c795d5075018e9ee45005799e6f/exercises/chapter3 を参照。

```
import Control.Plus (empty)
import Data.List (List(..), filter, head)
import Data.Maybe (Maybe)
```

`Control.Plus` モジュールは `purescript-control` パッケージに含まれているようですね。上記のコードはこの依存関係を解決できないので、ビルドできないですね……。 https://pursuit.purescript.org/packages/purescript-control/2.0.0/docs/Control.Plus

`Data.List` モジュールは `purescript-lists` パッケージに含まれているようですね。こちらはきちんと `bower install` されています。 https://pursuit.purescript.org/packages/purescript-lists/3.2.1/docs/Data.List

`Data.Maybe` モジュールは `purescript-maybe` パッケージに含まれているようですね。こちらは `purescript-lists` パッケージからの間接的な依存でなんとかビルドできるようですが、`bower install` したほうが良い気がします。 https://pursuit.purescript.org/packages/purescript-maybe/2.0.1/docs/Data.Maybe

あとで Pull Request を投げてみましょうかね……。→ [paf31/purescript-book][] は Pull Request 禁止のようです。 Issue で。

## PureScript by Example 3.3

`psci` の `:type` で、基本的な型に触れています。 [Language Guide の Types][purescript-language-guide-types] にあります。

Primitive Types が `Number` / `String` / `Boolean` ですね。これはスルー。

そして `Int` / `Array` / `Records` と。

`Int` は `Number` とは違い、整数に限定していますね。`Array` は要素の型が一致してないとダメです。 `Record` は JavaScript の `object` ですね。

```
> chapter3@1.0.0 pulp:psci /Users/bouzuya/.ghq/github.com/paf31/purescript-book/exercises/chapter3
> pulp psci

PSCi, version 0.10.2
Type :? for help

> :type 1
Int

> :type 1.0
Number

> :type [1, 2, 3]
Array Int

> :type [true, false]
Array Boolean

> :type [1, false]
Error found:
in module $PSCI
at  line 1, column 1 - line 1, column 11

  Could not match type

    Int

  with type

    Boolean


while inferring the type of [ 1
                            , false
                            ]
in value declaration it

See https://github.com/purescript/purescript/wiki/Error-Code-TypesDoNotUnify for more information,
or to contribute content related to this error.

> let author = { name: "Phil", interests: ["Functional Programming", "JavaScript"] }
> :type author
{ name :: String
, interests :: Array String
}

> author.name
"Phil"

> author.interests
["Functional Programming","JavaScript"]
```

Language Guide の Tagged Unions と Newtypes は飛ばして、Functions ですね。Tagged Unions や Newtype もすぐ出てくるはず……。

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

> :type const
forall a b. a -> b -> a
```

`psci` の `:paste` を見せつつ、関数定義の例のようです。

```
> :paste
… let
…   add :: Int -> Int -> Int
…   add x y = x + y
…
Error found:
in module $PSCI
at  line 3, column 13 - line 3, column 17

  Unknown operator (+)


See https://github.com/purescript/purescript/wiki/Error-Code-UnknownName for more information,
or to contribute content related to this error.

> import Prelude ((+))
> :paste
… let
…   add :: Int -> Int -> Int
…   add x y = x + y
…
> add 10 20
30

> import Prelude ((*))
> let mul = \x y -> x * y
> mul 10 20
200
```

`import Prelude` を限定していたので、 `(+)` が読まれていなかったですね。関数のリテラルである `\x -> x` の形式を見せる意図があったかもしれないので、ついでに `mul` も書いてみました。 [Language Guide の Functions][purescript-language-guide-functions] も置いておきます。

## PureScript by Example 3.4

`forall` の話。[Language Guide では Quantification][purescript-language-guide-quantification] かな。

↓の `flip` についている `forall` はこれが全称量化された型 (universally quantified type) ってことです、って説明されてますね。ぜんぜん分からないんですけど、任意の `a` `b` `c` について↓の型で動くってことなんじゃないですかね。

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

たとえば `a` `b` `c` には `Int` や `String` などがはいるので、`a` を `Int` 、 `b` を `String` 、 `c` を `String` にすると、次のようになる、と。

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

余談ですけど、型のこの表記は慣れないと困りますかね……。カリー化の話とかそのうち出てくるはずなので、スルーしますけど……。

`flip` に関して言うと関数を受け取って第一引数と第二引数を入れ替えた関数にする関数です。

```
> :reset
> import Prelude ((<>), flip, show)
> flip (\n s -> show n <> s) "Ten" 10
"10Ten"

> :type show
forall a. (Show a) => a -> String

> :type (<>)
forall a. (Semigroup a) => a -> a -> a
```

ふむ。

`show` は `Show` インスタンスを受け取って `String` を返す関数ですね。要するに `.toString()` 的なあれです。
https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Show#v:show


`(<>)` は `Semigroup` インスタンスをふたつ受け取ってくっつけて返します。`Array.prototype.concat` 的なあれです。 `(<>)` は `append` にたいしての operator alias です。これもそのうち出てくるはず……。
https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Semigroup#v:(%3C%3E)

これは書かれていますが、引数を逆にして `flip (\n s -> show n <> s) 10 "Ten"` にすると動きません。`show 10` の結果である `"10"` と `"Ten"` で `"10" <> "Ten"` するから動くのであって、`show "Ten"` の結果である `"\"Ten\""` と `10` を `<>` することはできません。型が違いますからね。

## PureScript by Example 3.5

インデントの注意。雰囲気でインデントしてますけど、大丈夫ですね……。基本は同じブロックなら同じインデント、改行できそうなところで見た目のために改行したいなら、ひとつ深くインデントしておけば大丈夫。ブロックが終わればインデントを浅くする感じですかね。文字で読んでもなんとなくピンとこないですし、ルールとして書くと難しい感じはしますけど、素朴にインデントすると動くような……。うーん。

一応 [Language Guide の Whitespace Rules][purescript-language-guide-whitespace-rules] を貼っておきます。

## まとめ

まだ 3 章の前半ですけど、疲れてきたので、今日はこのへんでおしまいです。

## 参考

- [PureScript by Example][purescript-by-example]
- [PureScript by Example - 3. Functions and Records][purescript-by-example-3]
- [paf31/purescript-book][]
- [Language Guide](https://github.com/purescript/purescript/wiki/Language-Guide)
- [Language Guide - Types][purescript-language-guide-types]
- [Language Guide - Functions][purescript-language-guide-functions]
- [Language Guide - Quantification][purescript-language-guide-quantification]
- [Language Guide - Whitespace Rules][purescript-language-guide-whitespace-rules]
- [Pursuit][pursuit]
- https://pursuit.purescript.org/packages/purescript-control/2.0.0/docs/Control.Plus
- https://pursuit.purescript.org/packages/purescript-lists/3.2.1/docs/Data.List
- https://pursuit.purescript.org/packages/purescript-maybe/2.0.1/docs/Data.Maybe
- https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Show#v:show
- https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Semigroup#v:(%3C%3E)

## 次回以降の TODO

- PureScript by Example & PureScript Language Guide を読み進める
- Tagged Unions / Newtype
- カリー化
- Infix Operator / operator alias
- `psc-package`
- PureScript IDE の導入
- [24 Days of PureScript, 2016][paf31/24-days-of-purescript-2016]
- [24 Days of PureScript, 2014](https://gist.github.com/paf31/8e9177b20ee920480fbc)
- 某氏の記事の紹介
- [github.com/purescript](https://github.com/purescript/) のコードを読む
- [github.com/purescript-node](https://github.com/purescript-node) のコードを読む
- [github.com/purescript-contrib](https://github.com/purescript-contrib) のコードを読む

[2016-12-01]: http://qiita.com/bouzuya/items/a5be85ec3e496e5bf436
[2016-12-02]: http://qiita.com/bouzuya/items/806335ea74ead0e33d95
[2016-12-03]: http://qiita.com/bouzuya/items/86cc9aaaddcc1aa790cf
[2016-12-04]: http://qiita.com/bouzuya/items/b2b80c22c50d0c1e739c
[2016-12-05]: http://qiita.com/bouzuya/items/f19ee0b86e9aec3f0afa
[2016-12-06]: http://qiita.com/bouzuya/items/4694ac25f68931115319
[2016-12-08]: http://qiita.com/bouzuya/items/7224535dd053c41748ed
[paf31/24-days-of-purescript-2016]: https://github.com/paf31/24-days-of-purescript-2016
[paf31/purescript-book]: https://github.com/paf31/purescript-book/tree/8ad7d2af75ad4c795d5075018e9ee45005799e6f
[pursuit]: https://pursuit.purescript.org/
[purescript/purescript-math]: https://github.com/purescript/purescript-math
[purescript-by-example]: https://leanpub.com/purescript/read
[purescript-by-example-3]: https://leanpub.com/purescript/read#leanpub-auto-functions-and-records
[purescript-by-example-ja]: http://hiruberuto.bitbucket.org/purescript/
[purescript-language-guide]: https://github.com/purescript/purescript/wiki/Language-Guide
[purescript-language-guide-types]: https://github.com/purescript/purescript/wiki/Language-Guide#types
[purescript-language-guide-functions]: https://github.com/purescript/purescript/wiki/Language-Guide#functions-1
[purescript-language-guide-quantification]: https://github.com/purescript/purescript/wiki/Language-Guide#quantification
[purescript-language-guide-whitespace-rules]: https://github.com/purescript/purescript/wiki/Language-Guide#whitespace-rules