PureScript by Example の 7.1, 7.2, 7.3, 7.4 を読む

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

- ← 23 日目『 [PureScript by Example の 6.11, 6.12, 6.13 を読む - Qiita][2016-12-23] 』
- → 25 日目『 [PureScript by Example の 7.5, 7.6, 7.7, 7.8 を読む - Qiita][2016-12-25] 』

## 概要

[PureScript by Example][purescript-by-example] を [PureScript Language Guide][language-guide] や [Pursuit][pursuit] を見ながら進めていく。

今日は 7.1, 7.2, 7.3, 7.4 を読む。ソースコードの例は [purescript-book の exercises/chapter7][purescript-book-chapter-7] にある。

※注意事項: 英語と日本語訳では大きな差異がある。`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][language-guide] 対象バージョン不明

## PureScript by Example 7.1

この章では applicative functor と traversable functor が出て来るらしい。例としては 3 章の電話帳をまた使うらしい。

Pursuit:

- [Applicative - Control.Applicative - purescript-prelude - Pursuit][pursuit-prelude-applicative]
- [Traversable - Data.Traversable - purescript-foldable-traversable - Pursuit][pursuit-foldable-traversable-traversable]

## PureScript by Example 7.2

`purescript-control` と `purescript-validation` を使うらしい。

Pursuit:

- [purescript-control - Pursuit][pursuit-control]
- [purescript-validation - Pursuit][pursuit-validation]

## PureScript by Example 7.3

例の通りに説明してみる。

下記のような `address` があるとき、 `Maybe` をとる形で使いたくなることはままある。

`address :: String -> String -> String -> AddressBook`

`Maybe` をとる形は次のような型になりそうだ。

`address' :: Maybe String -> Maybe String -> Maybe String -> Maybe AddressBook`

これを実装するには `Control.Apply` モジュールの `lift3` を使うと良いらしい。

`lift3 :: forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d`

Pursuit:

- [lift3 - Control.Apply - purescript-prelude - Pursuit][pursuit-prelude-lift3]

`Maybe` ではなく `Apply` だけど、`Maybe` も `Apply` のインスタンスなので問題ない。

Pursuit:

- [Maybe - Data.Maybe - purescript-maybe - Pursuit][pursuit-maybe-maybe]

```
> import Control.Apply (lift3)
> import Data.AddressBook (address)
> import Data.Maybe (Maybe(..))
> :t lift3
forall a b c d f. (Apply f) => (a -> b -> c -> d) -> f a -> f b -> f c -> f d

> :t address
String -> String -> String -> Address

> :t (lift3 address)
forall t1. (Apply t1) => t1 String -> t1 String -> t1 String -> t1 Address

> lift3 address (Just "123 Fake St.") Nothing (Just "CA")
Nothing

> lift3 address (Just "123 Fake St.") (Just "Faketown") (Just "CA")
(Just Address { street: "123 Fake St.", city: "Faketown", state: "CA" })
```

ふむ。ひとつでも `Nothing` だと `Nothing` になる。

## PureScript by Example 7.4

`lift3 :: forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d`

で出てくる `Apply` って何なの、という話。

```
class Functor f where
  map :: forall a b. (a -> b) -> f a -> f b

class Functor f <= Apply f where
  apply :: forall a b. f (a -> b) -> f a -> f b
```

`f` の中にない関数を `f` の中の `a` に適用する `map` と、`f` の中にある関数を `f` の中の `a` に適用する `apply` 。 `f` は今回だと `Maybe` 。

```
instance functorMaybe :: Functor Maybe where
  map f (Just a) = Just (f a)
  map f Nothing  = Nothing

instance applyMaybe :: Apply Maybe where
  apply (Just f) (Just x) = Just (f x)
  apply _        _        = Nothing
```

さきの例から想像できる範囲の実装。

で `lift3` の実装。それぞれ `map` は `<$>` 、 `apply` は `<*>` という operator が使われている。

```
forall a b c d f. (Apply f) => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
lift3 f x y z = f <$> x <*> y <*> z
```

順番に追っていけば確かに。

```
> import Data.AddressBook (address)
> import Data.Maybe (Maybe(..))
> import Prelude ((<$>), (<*>))
> address <$> Just "123 Fake St." <*> Nothing <*> Just "CA"
Nothing

> address <$> Just "123 Fake St." <*> Just "Faketown" <*> Just "CA"
(Just Address { street: "123 Fake St.", city: "Faketown", state: "CA" })
```

## まとめ

簡単に `Maybe` 対応できちゃうもんだなあ……。 `Functor` の `map` って聞くと戸惑うけど、JavaScript でも `Array` の `map` 使ってるんだよな……。

## 次回以降の TODO

- PureScript by Example & PureScript Language Guide を読み進める
- `Array` 以外での `do` 記法
- `psc-package`
- [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) のコードを読む

[purescript-by-example]: https://leanpub.com/purescript/read
[purescript-by-example-1]: https://leanpub.com/purescript/read#leanpub-auto-introduction
[purescript-by-example-2]: https://leanpub.com/purescript/read#leanpub-auto-getting-started
[purescript-by-example-3]: https://leanpub.com/purescript/read#leanpub-auto-functions-and-records
[purescript-by-example-4]: https://leanpub.com/purescript/read#leanpub-auto-recursion-maps-and-folds
[purescript-by-example-5]: https://leanpub.com/purescript/read#leanpub-auto-pattern-matching
[purescript-by-example-6]: https://leanpub.com/purescript/read#leanpub-auto-type-classes
[purescript-by-example-7]: https://leanpub.com/purescript/read#leanpub-auto-applicative-validation
[purescript-by-example-8]: https://leanpub.com/purescript/read#leanpub-auto-the-eff-monad
[purescript-by-example-9]: https://leanpub.com/purescript/read#leanpub-auto-canvas-graphics
[purescript-by-example-10]: https://leanpub.com/purescript/read#leanpub-auto-the-foreign-function-interface
[purescript-by-example-11]: https://leanpub.com/purescript/read#leanpub-auto-monadic-adventures
[purescript-by-example-12]: https://leanpub.com/purescript/read#leanpub-auto-callback-hell
[purescript-by-example-13]: https://leanpub.com/purescript/read#leanpub-auto-generative-testing
[purescript-by-example-14]: https://leanpub.com/purescript/read#leanpub-auto-domain-specific-languages

[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-07]: http://qiita.com/bouzuya/items/62c6ad30ecba3c68a7a3
[2016-12-08]: http://qiita.com/bouzuya/items/7224535dd053c41748ed
[2016-12-09]: http://qiita.com/bouzuya/items/868eafc19b96619c025a
[2016-12-10]: http://qiita.com/bouzuya/items/1a54ba3702f9818527a5
[2016-12-11]: http://qiita.com/bouzuya/items/ab2bc2d19461203f1ee5
[2016-12-12]: http://qiita.com/bouzuya/items/c42ddb14477716de1dcf
[2016-12-13]: http://qiita.com/bouzuya/items/a49463871a96459d7083
[2016-12-14]: http://qiita.com/bouzuya/items/14ca2a2cd9c0bb01653d
[2016-12-15]: http://qiita.com/bouzuya/items/0511f040381c6c2eba12
[2016-12-16]: http://qiita.com/bouzuya/items/10d8f935c0e5695826c5
[2016-12-17]: http://qiita.com/bouzuya/items/129b2ab8ba3fa89edaf5
[2016-12-18]: http://qiita.com/bouzuya/items/ae7ce46363d0ccdfb03b
[2016-12-19]: http://qiita.com/bouzuya/items/ade348495b755d57ede0
[2016-12-20]: http://qiita.com/bouzuya/items/6e3cc11aa8387b4a5254
[2016-12-21]: http://qiita.com/bouzuya/items/b7e04a015084eb1e8d32
[2016-12-22]: http://qiita.com/bouzuya/items/92d21ee3bbfde3399888
[2016-12-23]: http://qiita.com/bouzuya/items/6e49ad627da276263075
[2016-12-24]: http://qiita.com/bouzuya/items/6ca3841bba3ab460542e
[2016-12-25]: http://qiita.com/bouzuya/items/513f1f8ab0aeca0ea76a

[pursuit-prelude-show]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Show#t:Show
[pursuit-foldable-traversable-foldable]: https://pursuit.purescript.org/packages/purescript-foldable-traversable/2.0.0/docs/Data.Foldable#t:Foldable
[pursuit-maybe-maybe]: https://pursuit.purescript.org/packages/purescript-maybe/2.0.1/docs/Data.Maybe#t:Maybe
[pursuit-monoid-monoid]: https://pursuit.purescript.org/packages/purescript-monoid/2.2.0/docs/Data.Monoid#t:Monoid
[pursuit-prelude-eq]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Eq#t:Eq
[pursuit-prelude-field]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Field#t:Field
[pursuit-prelude-functor]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Functor#t:Functor
[pursuit-prelude-ord]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Ord#t:Ord
[pursuit-prelude-semigroup]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Data.Semigroup#t:Semigroup
[pursuit-arrays-head]: https://pursuit.purescript.org/packages/purescript-arrays/3.1.0/docs/Data.Array.Partial#v:head
[pursuit-partial-unsafe-partial]: https://pursuit.purescript.org/packages/purescript-partial/1.1.2/docs/Partial.Unsafe#v:unsafePartial
[pursuit-either-either]: https://pursuit.purescript.org/packages/purescript-either/2.0.0/docs/Data.Either#t:Either

[pursuit-maybe-maybe]: https://pursuit.purescript.org/packages/purescript-maybe/2.0.1/docs/Data.Maybe#t:Maybe
[pursuit-prelude-lift3]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Control.Apply#v:lift3
[pursuit-control]: https://pursuit.purescript.org/packages/purescript-control/2.0.0
[pursuit-foldable-traversable-traversable]: https://pursuit.purescript.org/packages/purescript-foldable-traversable/2.0.0/docs/Data.Traversable#t:Traversable
[pursuit-prelude-applicative]: https://pursuit.purescript.org/packages/purescript-prelude/2.1.0/docs/Control.Applicative#t:Applicative
[pursuit-validation]: https://pursuit.purescript.org/packages/purescript-validation/2.0.0

[paf31/24-days-of-purescript-2016]: https://github.com/paf31/24-days-of-purescript-2016
[purescript/purescript]: https://github.com/purescript/purescript
[pursuit]: https://pursuit.purescript.org/
[purescript/documentation]: https://github.com/purescript/documentation
[purescript-by-example-6]: https://leanpub.com/purescript/read#leanpub-auto-type-classes
[purescript-by-example-ja]: http://hiruberuto.bitbucket.org/purescript/
[try-purescript]: http://try.purescript.org/
[language-guide]: https://github.com/purescript/documentation/tree/f48ba1ee7761446e1ae75ee806e51688c1937297/language/
[paf31/purescript-book]: https://github.com/paf31/purescript-book/tree/8ad7d2af75ad4c795d5075018e9ee45005799e6f/
[purescript-book-chapter-7]: https://github.com/paf31/purescript-book/tree/8ad7d2af75ad4c795d5075018e9ee45005799e6f/exercises/chapter7