Data.Tree モジュールで Applicative の情報を info で見ると、Tree a 型のデータに pure, <*>, *>, <* の四つの関数が使えることがわかる。<$> 関数がないが、これは pure <*> と同じだ。
Prelude Data.Tree> :info Applicative class Functor f => Applicative (f :: * -> *) where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b (*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a -- Defined in ‘GHC.Base’ instance Applicative (Either e) -- Defined in ‘Data.Either’ instance Applicative Tree -- Defined in ‘Data.Tree’ instance Applicative [] -- Defined in ‘GHC.Base’ instance Applicative Maybe -- Defined in ‘GHC.Base’ instance Applicative IO -- Defined in ‘GHC.Base’ instance Applicative ((->) a) -- Defined in ‘GHC.Base’ instance Monoid a => Applicative ((,) a) -- Defined in ‘GHC.Base’ それではそれぞれの関数が Tree a 型のデータではどのように現れるかを見てみよう。まずは、pure 関数だ。これは Monad の return 関数と同じで生のデータをデータ型に包む働きがある。 まず生の自然数を pure 関数で Tree 型のデータに梱包してみよう。ただし、上の表示でわかるように pure 関数は Either e 型や、リスト型、Maybe 型、IO 型のように色々なデータ型に対応している。したがって自然数を pure 関数を使って Tree a 型にするには、:: Tree Int による型指定が必要になる。 Prelude Data.Tree> pure 1 :: Tree Int Node {rootLabel = 1, subForest = []} このように Tree a 型では pure 関数で rootLabel = 1 で子ノードのない木構造が返されることがわかる。Monad の return でモナドのデータを作ることができるのは生のデータだけだったが、Applicative の pure の場合は関数も Applicative 型に包み込むことができる。 Prelude Data.Tree> :t pure (*2) pure (*2) :: (Num a, Applicative f) => f (a -> a) Applicative に包まれた関数は <*> 演算子で Tree a 型のデータに関数適用できる。この場合 Tree a のコンテナのデータに Applicative に包まれた関数が関数適用される。 Prelude Data.Tree> let a = pure 1 :: Tree Int Prelude Data.Tree> a Node {rootLabel = 1, subForest = []} Prelude Data.Tree> pure (*2) <*> a Node {rootLabel = 2, subForest = []} 木構造のデータが子ノードを持っているときは (*2) はそれらのノード全てにも適用される。 Prelude Data.Tree> let b = Node 1 [Node 2 [], Node 3 []] Prelude Data.Tree> b Node {rootLabel = 1, subForest = [Node {rootLabel = 2, subForest = []},Node {rootLabel = 3, subForest = []}]} Prelude Data.Tree> pure (*2) <*> b Node {rootLabel = 2, subForest = [Node {rootLabel = 4, subForest = []},Node {rootLabel = 6, subForest = []}]} Tree a のコンテナの値を2倍にするだけだったら fmap でもできる。 Prelude Data.Tree> fmap (*2) b Node {rootLabel = 2, subForest = [Node {rootLabel = 4, subForest = []},Node {rootLabel = 6, subForest = []}]} しかし Applicative なら2引数の関数の場合も適用できる。 Prelude Data.Tree> pure (+) <*> pure 10 <*> b Node {rootLabel = 11, subForest = [Node {rootLabel = 12, subForest = []},Node {rootLabel = 13, subForest = []}]} これには関数のカリー化が関係している。pure (+) を pure 10 に関数適用すると、1引数の関数(Applicative に梱包されたものだが)になる。 Prelude Data.Tree> :t pure (+) <*> pure 10 pure (+) <*> pure 10 :: (Num a, Applicative f) => f (a -> a) したがって、これをさらに Tree a 型の b にカスケードに関数適用することによって、最初の Tree a 型のデータが得られる。 *> は Monad の時の >> と同じで左項の値は右項に渡されない。 Prelude Data.Tree> pure (*2) *> a Node {rootLabel = 1, subForest = []} <* は逆に右項の値が無視される。 Prelude Data.Tree> :t pure (+) <*> pure 10 <* a pure (+) <*> pure 10 <* a :: Num a => Tree (a -> a) このように上の結果は Tree a 型のデータではなく1引き数関数になるから、もう一回引数を与えると Tree a 型のデータになる。 Prelude Data.Tree> pure (+) <*> pure 10 <* a <*> b Node {rootLabel = 11, subForest = [Node {rootLabel = 12, subForest = []},Node {rootLabel = 13, subForest = []}]} 最後に pure (+) の引数にどちらも Tree a 型を与えるとどうなるだろうか。 Prelude Data.Tree> pure (+) <*> b <*> b Node {rootLabel = 2, subForest = [Node {rootLabel = 3, subForest = []},Node {rootLabel = 4, subForest = []},Node {rootLabel = 3, subForest = [Node {rootLabel = 4, subForest = []},Node {rootLabel = 5, subForest = []}]},Node {rootLabel = 4, subForest = [Node {rootLabel = 5, subForest = []},Node {rootLabel = 6, subForest = []}]}]} なぜ、このような結果になるのかよくわからなかったが、これは次の関数 printTree を定義して適用すると分かりやすい。表示は省略する。 Prelude Data.Tree> let printTree = putStr . drawTree . (fmap show) Prelude Data.Tree> printTree $ pure (+) <*> b <*> b Data.Tree モジュールの木構造のデータ Tree a 型を活用するという目的の他にも、色々なタイプクラスの関数のふるまいを知るという目的にも Data.Tree モジュールの探索は有用だ。
by tnomura9
| 2016-10-16 22:57
| Haskell
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||