2016-08-31 5 views
0

私は3つのモナディック関数を用意しています。それらは一緒に構成し、条件付きで述語に分岐したいと考えています。私は多分一般のトレードオフを持つソリューションを探しています。矢印(ArrowChoice?)とMonadsは有望視されています。これらの3種類の関数を条件分岐のために構成する一般的な方法は何ですか?

不自然な問題はこれです:私は、多くのお客様の 『個人番号』を追跡してサービスを実行

。最初にログインした場合、その番号は0に設定されています。以前ログインしていて、おそらく番号が変更されている場合は、その番号がフェッチされます。

したがって、このプログラムの汎用タイプはprogram :: Name -> Intです。私は他人のために、これらの機能を入れ替えることができるようにしたい

new?  :: Name -> Bool 
fetch :: Name -> Int 
generate :: Name -> Int 

は、私はすべてのデータの永続ストアに問い合わせるモナド影響を与える可能性があります3つの機能、(例えばDB、国家を)持っています。たとえば、fetchFromDB、またはfetchFromStateMonadの場合はfetchをスワップアウトします。それらを「構成」の

一つの解決策は、次のようになります。

ex1 :: (a -> Bool) -> (a -> b) -> (a -> b) -> (a -> b) 
-- or -- 
ex1 :: (Name -> Bool) -> (Name -> Int) -> (Name -> Int) -> (Name -> Int) 
--  predicate   fetch   generate   result 

これは、一般的な解決策に私が近づくifMのようなビットを探します。

しかし、ex1 "John"を呼び出すと、述語を決定するために1つのデータベース呼び出しが行われ、もう1つはfetchジョンの番号になります。 (もちろん、これはこの狭いケースでは簡単に解決できます。より一般的なものを探しています)。

ex2 :: Name -> (Name -> Bool) -> (Name -> Int) -> (Name -> Int) -> Int 
--  name predicate   fetch   generate  result   

それは、predicatefetch介して1つのデータベースクエリの結果をスレッド化する方法をまだ私には明らかではないが、少なくともこのタイプの署名は、それを可能にすることができます。今は型のシグネチャの問題がありますが、それは合成のようなものではありませんし、さらには特別なものです。

この問題を一般化する方法はありますか?いくつかのcomposition関数は、任意の述語や関数を意図した方法で結びつけるために必要なすべてを行います。

+0

なぜdownvotes? –

答えて

2

new?fetchが別々の関数である場合、いずれの場合も2つのクエリを作成する必要があります。 (名前がデータベースにあるかどうかを調べるために1つ、結果を調べた後に別の名前を調べる)。

しかし、new?は冗長です。 fetchMaybe値を返して、希望番号を取得するか、名前が新しいことを示すことができます。また、あなたのモナドがMonadIOのインスタンスであると仮定すると、あなたの署名と関数は次のようなものになります

program :: MonadIO m => Name     -- name to query 
        -> (Name -> m Maybe Int) -- fetch 
        -> (Name -> m Int)  -- generate 
        -> m Int     -- number for name 
program name fetch generate = fetch name >>= maybe (generate name) return 
関連する問題