のモナドを定義するには、次の3 つの法則に従って、との(->) r
2 つの操作が必要です。return
(>>=)
instance Monad ((->) r) where
返品の署名を見ると(->) r
return :: a -> r -> a
2 番目の引数を無視する単なる定数関数であることがわかります。
return a r = a
または、代わりに、
return = const
を構築する(>>=)
には、その型シグネチャをモナドで特殊化すると(->) r
、
(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b
実際には可能な定義は 1 つだけです。
(>>=) x y z = y (x z) z
このモナドを使用することはr
、すべての関数に追加の引数を渡すようなものです。これを構成に使用したり、オプションをプログラムの内部に深く渡したりすることができます。
3 つのモナド法則を検証することで、それがモナドであることを確認できます。
1. return a >>= f = f a
return a >>= f
= (\b -> a) >>= f -- by definition of return
= (\x y z -> y (x z) z) (\b -> a) f -- by definition of (>>=)
= (\y z -> y ((\b -> a) z) z) f -- beta reduction
= (\z -> f ((\b -> a) z) z) -- beta reduction
= (\z -> f a z) -- beta reduction
= f a -- eta reduction
2. m >>= return = m
m >>= return
= (\x y z -> y (x z) z) m return -- definition of (>>=)
= (\y z -> y (m z) z) return -- beta reduction
= (\z -> return (m z) z) -- beta reduction
= (\z -> const (m z) z) -- definition of return
= (\z -> m z) -- definition of const
= m -- eta reduction
最終的なモナド法則:
3. (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
同様の簡単な等式推論が続きます。
((->) r) の他の多くのクラスも定義できます。
instance Functor ((->) r) where
の署名を見ると
-- fmap :: (a -> b) -> (r -> a) -> r -> b
単なる構成であることがわかります。
fmap = (.)
同様に、次のインスタンスを作成できます。Applicative
instance Applicative ((->) r) where
-- pure :: a -> r -> a
pure = const
-- (<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
(<*>) g f r = g r (f r)
これらのインスタンスを持つことの良いところは、関数を操作するときにMonadとApplicativeコンビネータのすべてを使用できることです。
(->) を含むクラスのインスタンスはたくさんあります。たとえば、次のように Monoidが与えられた場合、(b -> a)のMonoidのインスタンスを手書きできますa
。
enter code here
instance Monoid a => Monoid (b -> a) where
-- mempty :: Monoid a => b -> a
mempty _ = mempty
-- mappend :: Monoid a => (b -> a) -> (b -> a) -> b -> a
mappend f g b = f b `mappend` g b
しかし、Monad/Applicative インスタンスが与えられた場合、このインスタンスを次のように定義することもできます
instance Monoid a => Monoid (r -> a) where
mempty = pure mempty
mappend = liftA2 mappend
Applicative インスタンスを for(->) r
または with で使用する
instance Monoid a => Monoid (r -> a) where
mempty = return mempty
mappend = liftM2 mappend
の Monad インスタンスを使用します(->) r
。
ここでの節約は最小限ですが、たとえば、#haskell IRC チャネルの lambdabot によって提供される、ポイントフリー コードを生成するための @pl ツールは、これらのインスタンスをかなり乱用します。