この記事は (bouzuya) PureScript Advent Calendar 2016 の 25 日目。 (bouzuya) PureScript Advent Calendar 2016 は bouzuya の PureScript 学習の記録だ。
概要
PureScript by Example を PureScript Language Guide や Pursuit を見ながら進めていく。
今日は 7.5, 7.6, 7.7, 7.8 を読む。ソースコードの例は 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 対象バージョン不明
この章のおさらい
Applicative
型クラスと Traversable
型クラスを見るらしい。 Control.Apply
の lift3
の実装を基に Functor
型クラスと Apply
型クラスの関数を調べた。
Pursuit:
- Applicative - Control.Applicative - purescript-prelude - Pursuit
- Traversable - Data.Traversable - purescript-foldable-traversable - Pursuit
PureScript by Example 7.5
Applicative
型クラス。 Apply
に加えて pure
を持つ。 Maybe
は Applicative
のインスタンスでもある。
class Apply f <= Applicative f where
pure :: forall a. a -> f a
instance applicativeMaybe :: Applicative Maybe where
pure x = Just x
a -> f a
なので、 f
で a
を包んで返す感じ。 Maybe
だと Just
するだけ。
Pursuit:
PureScript by Example 7.6
なんだかふわふわした説明だ……。
PureScript の関数は純粋で副作用をサポートしていないけど、 applicative functor は関手 (functor) f
によってエンコードされたなんらかの副作用をサポートする、より大きなプログラミング言語にできる。ふむー。
Maybe
によって Nothing
を導入できるってのがその例らしい。
pure
はその大きなプログラミング言語に値を持ち上げるし、 map
や apply
で関数も、と。ふむー。
分かるような分からないような……。
PureScript by Example 7.7
> import Prelude
> let fullName first middle last = last <> ", " <> first <> " " <> middle
上記のような fullName
をつくって Maybe
のために使うことは難しくないと分かった。7.7 ではエラーの内容を知るために Either
を使う例が挙げられている。
module Main where
import Prelude
import Data.Maybe
import Data.Either
fullName :: String -> String -> String -> String
fullName first middle last = last <> ", " <> first <> " " <> middle
withError :: forall a. Maybe a -> String -> Either String a
withError Nothing err = Left err
withError (Just a) _ = Right a
fullNameEither :: Maybe String -> Maybe String -> Maybe String -> Either String String
fullNameEither first middle last =
fullName <$> (first `withError` "First name was missing")
<*> (middle `withError` "Middle name was missing")
<*> (last `withError` "Last name was missing")
どれかが Left
なら最終結果も Left
。すべて Right
なら Right
。
実用の面で問題があるとすれば、最初のエラーしか取れないこと。その解決策もこの章の後半で出てくるらしい。
PureScript by Example 7.8
ここまでで a -> a -> a -> List a
が書けるなら f a -> f a -> f a -> f (List a)
は難しくないことが分かっている。 f a -> f a -> f a
を固定ではなく可変にして List (f a)
にすると List (f a) -> f (List a)
にできる。ふむ。
module Main where
import Prelude
import Data.List
combineList :: forall f a. Applicative f => List (f a) -> f (List a)
combineList Nil = pure Nil
combineList (Cons x xs) = Cons <$> x <*> combineList xs
うん。そうだね。
> import Data.List
> import Data.Maybe
> import Main
> combineList (fromFoldable [Just 1, Just 2, Just 3])
(Just (1 : 2 : 3 : Nil))
> combineList (fromFoldable [Just 1, Nothing, Just 2])
Nothing
確かに動く。Maybe
でなくても動くらしい。そりゃ Applicative
だもんな。
combineList :: forall f a. Applicative f => List (f a) -> f (List a)
また Traversable
の話の中でこの combineList
が出てくるらしい。ふむ。
まとめ
とりあえず Applicative
の例まで。
すごく途中だけど、これで (bouzuya) PureScript Advent Calendar 2016 の 25 日はおしまい。「 PureScript by Example を読む」に関しては、ペースは落ちるけど、章単位で書くようにして最後まで進めるつもりだ。
次回以降の 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 のコードを読む