この記事は (bouzuya) PureScript Advent Calendar 2016 の 24 日目。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録だ。
- ← 23 日目『 PureScript by Example の 6.11, 6.12, 6.13 を読む - Qiita 』
- → 25 日目『 PureScript by Example の 7.5, 7.6, 7.7, 7.8 を読む - Qiita 』
概要
PureScript by Example を PureScript Language Guide や Pursuit を見ながら進めていく。
今日は 7.1, 7.2, 7.3, 7.4 を読む。ソースコードの例は purescript-book の exercises/chapter7 にある。
※注意事項: 英語と日本語訳では大きな差異がある。0.10.x
に対応している英語の側で進める。
- PureScript by Example 2016-12-05 時点で 0.10.x 向け
- 実例による PureScript 2016-12-05 時点で 0.7 向け
- PureScript Language Guide 対象バージョン不明
PureScript by Example 7.1
この章では applicative functor と traversable functor が出て来るらしい。例としては 3 章の電話帳をまた使うらしい。
Pursuit:
- Applicative - Control.Applicative - purescript-prelude - Pursuit
- Traversable - Data.Traversable - purescript-foldable-traversable - Pursuit
PureScript by Example 7.2
purescript-control
と purescript-validation
を使うらしい。
Pursuit:
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:
Maybe
ではなく Apply
だけど、Maybe
も Apply
のインスタンスなので問題ない。
Pursuit:
> 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
- 24 Days of PureScript, 2014
- 某氏の記事の紹介
- github.com/purescript のコードを読む
- github.com/purescript-node のコードを読む
- github.com/purescript-contrib のコードを読む