上記のとおりです。
『すごいH』本を読みながら、リストだとかMaybe
だとかEither
だとかがFunctor
、Applicative
などを満たしていることを各法則を試すことによって確認しています。
具体的な課題はこんな感じ
課題
次の型がそれぞれ下に列挙された型クラスのインスタンスであることを示せ
(具体的には各型クラスの法則を満たすことを示せば良い)
[a]
Functor
Applicative
Monoid
Monad
Foldable
Maybe a
Functor
Applicative
Monoid
Monad
Either e a
Functor
Applicative
Monad
(->)
Functor
Applicative
Monad
Monoid
(a, b)
Monad
(((,) a)
がMonad
)Monoid
Writer w a
Monad
なお、各型クラスの法則は以下のとおり
Functor
則
-- idで値を写した場合、ファンクター値が変化してはいけない fmap id f == f -- 二つの関数gとhについて、「gとhの合成関数で写したもの」と -- 「hで写したファンクター値をgに適用したもの」とが一致しなければならない fmap (g.h) f == (fmap g . fmap h) f
Applicative
則
-- Functorとのインターオペラビリティ pure f <*> x == fmap f x -- pure idを適用しても値が変化してはいけない pure id <*> x == x -- 合成順序を変えても結果が変わってはならない pure (.) <*> u <*> v <*> w == u <*> (v <*> w) -- pureでApplicativeにした値でpureでApplicativeにした値を写したものと、 -- 先に写したものをpureでApplicativeにしたものとは一致しなければならない pure f <*> pure x == pure (f x) -- $関数 u <*> pure y == pure ($ y) <*> u
Monoid
則
-- empty値にappendした場合、値が変化してはいけない memempty `mappend` x == x -- 値にempty値をappendした場合、値が変化してはいけない x `mappend` mempty == x -- 結合則 (x `mappend` y) mappend z == x `mappend` (y `mappend` z)
Monad
則
-- 左恒等性 -- returnでMonadにした値に関数をbindした結果は -- 値を関数に適用したものと一致しなければならない return x >>= f == f x -- 右恒等性 -- returnをbindしたモナド値は変化してはいけない m >>= return == m -- 結合法則 -- モナド値をモナド関数に適用する式を評価するときに、入れ子の順序はどうでもよく、 -- ただ関数の意味だけが重要であるということ m >>= f >>= g == m >>= (\x -> f x >>= g)
なお、参考までにList
がMonoid
であることを確認するhpecはこんな感じ。
module List.MonoidSpec ( spec ) where import Test.Hspec.Core.Spec import Test.Hspec.Expectations import Data.Monoid import Control.Monad (mapM_) import List.TestData spec :: Spec spec = do describe "List satisfies Monoid law" $ do describe "law1 : mempty `mappend` x == x" $ do mapM_ (itSatisfies law1LF id) testLists describe "law2 : x `mappend` mempty == x" $ do mapM_ (itSatisfies law2LF id) testLists describe "law3 : mappend bounding : (x <> y) <> z == x <> (y <> z)" $ do mapM_ (itSatisfies law3LF law3RF) testLists unit :: [a] unit = mempty law1LF :: [a] -> [a] law1LF xs = unit <> xs law2LF :: [a] -> [a] law2LF xs = xs <> mempty law3LF :: [Int] -> [Int] law3LF xs = ([1] <> [2,3]) <> xs law3RF :: [Int] -> [Int] law3RF xs = [1] <> ([2,3] <> xs)
まあ、ただ純粋なあれだけをやってても、アウトプットにならないので、この証明が終わったら、Yesodとかやってみたいと思うのだけど、ちょっと趣味っぽいアプリも作りたいので、自分のインスタンスが複数あればいいなと思ったりしている。
おわり