すごいHaskell本のメモ
FunctorやらMonadまわりのメモ。
Functor
箱と比喩されている。リストやMaybeなど大体Functor。
fmapをもってる。(Scalaでいうmap)
fmap :: Functor f => (a -> b) -> f a -> f b
aをとりbを返す関数と、Functor値aをとる。aに関数を適用してFunctor値bを返す。
Prelude> fmap (+1) (Just 1) Just 2
しかしFunctorだと中の関数に何かしようとすると辛くなる。
Prelude> let a = fmap (+) (Just 1) Prelude> :t a a :: Maybe (Integer -> Integer) 部分適用(カリー)されてMaybeの中に関数が入っている Prelude> fmap (\f -> f 1) a Just 2
これを簡単にできるのが↓
Applicative
文脈と比喩されている。リストやMaybeもまたApplicative。
pureと<*>を持っている。
Prelude> import Control.Applicative
pureは、aを受け取りapplicative aを返すだけの関数。
Prelude Control.Applicative> :t pure pure :: Applicative f => a -> f a
<*>は
Prelude Control.Applicative> :t (<*>) (<*>) :: Applicative f => f (a -> b) -> f a -> f b Appricativeに入った関数を受け取るところがFunctorと違う。 Prelude Control.Applicative> Just (+1) <*> Just 1 Just 2
functorで辛かった部分をapplicativeで書くと、
Prelude Control.Applicative> fmap (+) (Just 1) <*> Just 1 Just 2 短く書くこともできる↓ Prelude Control.Applicative> (+) <$> (Just 1) <*> Just 1 Just 2
簡単に書けた。
関数のApplicative
関数の<*>は、
f <*> g = \x -> f x (g x)
: fとgの関数を受け取り、g xした結果とxをfに渡す関数を返す
Prelude Control.Applicative> (+) <$> (+1) <*> (+1) $ 1 4
??
(+) <$> (+1) = (1 + a) + b (+) <$> (+1) <*> (+1) = \x -> (1 + x) + (1 + x) これに1を渡すと、4
たしかに4だ。
リストのApplicative
Prelude Control.Applicative> (+) <$> [1,2,3] <*> [2,3,4] [3,4,5,4,5,6,5,6,7]
それぞれに適用される。
ペアで適用したいときは、
Prelude Control.Applicative> getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [2,3,4] [3,5,7]
liftA2
Prelude Control.Applicative> :t liftA2 liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
aとbをとりcを返す関数と、Applicative値aとApplicative値bをとり、Applicative値cを返す関数。
Prelude Control.Applicative> liftA2 (+) (Just 1) (Just 2) Just 3
↓より↑のほうが分かりやすい。
Prelude Control.Applicative> (+) <$> (Just 1) <*> (Just 2) Just 3
Monoid
Monadとは別物。
ok : 1 + (2 + 3) == (1 + 2) + 3 (++や*など) ng : 1 - (2 - 3) == (1 - 2) - 3 みたいに順番変わってもokなもの
リストなら[]。(+)なら0。など
例
Prelude> import Data.Monoid Prelude Data.Monoid> [1,2] `mappend` [3,4] [1,2,3,4] Prelude Data.Monoid> "ab" `mappend` "cd" "abcd"
その他いろいろ
-- Sum, Product Prelude Data.Monoid> (Sum 1) `mappend` (Sum 2) Sum {getSum = 3} Prelude Data.Monoid> (Product 2) `mappend` (Product 2) Product {getProduct = 4} Prelude Data.Monoid> getProduct $ (Product 2) `mappend` (Product 2) 4 -- Any, All Prelude Data.Monoid> (Any True) `mappend` (Any False) Any {getAny = True} Prelude Data.Monoid> (All True) `mappend` (All False) All {getAll = False} -- compareは左側がEQのときに右側を評価 Prelude Data.Monoid> LT `mappend` GT LT Prelude Data.Monoid> EQ `mappend` GT GT
Foldable
畳み込むアレ
型
Prelude Data.Monoid> import Data.Foldable as F Prelude Data.Monoid F> :t F.foldl F.foldl :: Foldable t => (a -> b -> a) -> a -> t b -> a
例
Prelude Data.Monoid F> F.foldl (+) 0 [1,2,3] 6 Prelude Data.Monoid F> F.foldl (+) 1 (Just 1) 2
Monad
噂のアレ
Applicativeのupgrade版
型
-- pureと同じようにreturnがある Prelude> :t return return :: Monad m => a -> m a -- バインドと呼ばれる。scalaでいうflatMap。 Prelude> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b
例
Prelude> Just 1 >>= \x -> Just (x + 1) Just 2 Prelude> [1,2,3] >>= \x -> [x + 1] [2,3,4] Prelude> [1,2,3] >>= \x -> if x > 1 then [x] else [] [2,3] Prelude> Just 1 >>= \x -> Just (x+x) >>= \x -> Just (x*x) >>= \x -> if x > 10 then Just x else Nothing Nothing -- Scalaだと scala> Some(1) flatMap { x => Some(x+x) } flatMap { x => Some(x*x) } flatMap { x => if (x > 10) Some(x) else None } res6: Option[Int] = None
『あーScalaのアレと同じか』というのがちょいちょいあって助かる。