39

(->)さまざまな質問で、たとえばポイントフリー スタイルを実現するためにモナドのインスタンスを使用することに関するヒントをコメントで見つけました。

私の場合、これは少し抽象的すぎます。わかりました、私は Arrow インスタンスがオン(->)になっているのを見てきましたが、それ(->)はインスタンス表記では使用できますが、型宣言では使用できないようです (それは別の質問のためだけのものです)。

(->)モナドのインスタンスとして使用する例はありますか? それとも良いリンクですか?

この質問がすでにここで議論されている場合は申し訳ありませんが、(->)モナドインスタンス」を検索すると、想像できるほど多くのヒットが得られます...Haskellに関するほとんどすべての質問は(->)「モナド」に関係しているためです。

4

2 に答える 2

36

特定の typerの場合、 type の関数は、typed の環境を使用して をr -> a提供する計算と考えることができます。2 つの関数とが与えられた場合、環境 (再び型 ) が与えられたときにこれらを構成できることは容易に想像できます。arr -> aa -> (r -> b)r

ちょっと待って!それがまさにモナドのことです!

したがって、 と の両方にを渡すことで、(->) rその実装の Monad のインスタンスを作成できます。これが Monad インスタンスが行うことです。f >>= grfg(->) r

環境に実際にアクセスするには、 を使用できますid :: r -> r。これは、環境で実行され、rを配信する計算と考えることができますr。ローカル サブ環境を作成するには、以下を使用できます。

inLocalEnvironment :: (r -> r) -> (r -> a) -> (r -> a)
inLocalEnvironment xform f = \env -> f (xform env)

環境を計算に渡してローカルでクエリおよび変更できるこのパターンは、(->) rモナドだけでなく、MonadReaderここで使用したものよりもはるかに適切な名前を使用してクラスに抽象化される理由です。

http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control-Monad-Reader-Class.html

基本的に、これには 2 つのインスタンスがあります:(->) rここで見たものとReaderT r m、これは単なるnewtypeラッパーであり、ここで説明r -> m aしたモナドと同じですが、(->) r他の変換されたモナドで計算を提供します。

于 2011-03-15T10:39:34.640 に答える
28

のモナドを定義するには、次の3 つの法則に従って、との(->) r2 つの操作が必要です。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)

これらのインスタンスを持つことの良いところは、関数を操作するときにMonadApplicativeコンビネータのすべてを使用できることです。

(->) を含むクラスのインスタンスはたくさんあります。たとえば、次のように 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 ツールは、これらのインスタンスをかなり乱用します。

于 2011-03-15T19:07:36.380 に答える