7

モナドを使いたいとしましょう。それから、リスト内でルックアップをしたいとしReaderT [(a,b)]ます。Maybe

これを行う簡単で、あまり珍しくない方法は次のとおりです。

最初の可能性

find a = ReaderT (lookup a)

ただし、これは、ReaderT トランスフォーマーがどのように機能するかについて、自明ではないことを主張しているように見えます。Control.Monad.Reader のソース コードを見ると、これが問題なく動作することが明らかです。しかし、これを裏付けるドキュメントを読んだことがありません。しかし、次のように find を書くこともできます:

第二の可能性

find a = do  y <- ask 
             lift (lookup a y)

MaybeT同様のアイデアは、 、StateTStateおよびのラッピングにも適用されReaderます。通常、私は最初の例のように書きますが、ほとんどの場合、2 番目の例のように書く方法は明らかであり、読みやすいとさえ言えます。だから私の質問は: 最初の例のようなコードは悪いと考えるべきですか?

4

3 に答える 3

9

最初の方法の最大の問題は次のとおりだと思います。

mtl の作成者 (または使用する任意のトランスフォーマー ライブラリ) が ReaderT のデータ コンストラクターのエクスポートを停止することを決定した場合、それは機能しなくなります。これは、mtl 1 から mtl 2 へのバージョン バンプの State モナドで発生し、非常に厄介です。一方、askReader の公式 API の一部であり、それを維持することを計画する必要があります。

一方、最初の方法が間違っているとは思いません。

于 2010-11-30T18:54:38.167 に答える
3

mtlライブラリの現在のバージョン ( transformersライブラリに基づく) は、単純なモナドreader :: (r -> a) -> Reader r aを使用するときに、まさにこの目的のために関数をエクスポートします。Readerしたがって、ライブラリの設計ではこの使用法が考慮されていることがわかります。にはそのような関数が提供されていないため、これを行うために公式にサポートされている方法は、コンストラクターを直接使用することReaderTであるとある程度確信を持って言えます。ReaderT

readerT :: Monad m => (r -> a) -> ReaderT r m aライブラリに類似のものを追加する必要があるというあなたの意見に同意します。これは、一貫性のためにも、誰かのコードを壊すことなく内部表現をいつか変更できるようにするためにも良いことです。

しかし、今のところ、あなたの「最初の可能性」が進むべき道です。

于 2010-12-05T10:26:25.777 に答える
3

少なくとも速度の違いはあります。

状態として乱数生成を使用し、実行中に約 5000000 の乱数値を生成する必要があるプログラムを作成しました。次に、サイコロを振る次の 2 つの関数について考えてみましょう。

random16  = State $ randomR (1,6) -- Using the internal representation
random16' = do
            s <- get
            (r,s') <- randomR (1,6) s
            put s'
            return r

最初のプログラムは約 6 秒で実行されますが、2 番目のプログラムはさらに遅く、約 8 秒かかります。リーダーに似ていると想像できるので、ランタイムが重要な場合は、より明確なものの代わりにこれを使用してください。これには厳格なバージョンを使用しました。

于 2010-12-01T06:02:45.750 に答える