11

これは、ここでの私のモジュールに関連する質問であり、少し簡略化されています。これは、この前の質問にも関連しています。この質問では、問題を単純化しすぎて、探していた答えが得られませんでした。これがあまり具体的ではないことを願っています。より良いものかどうか考えられる場合は、タイトルを変更してください。

バックグラウンド

私のモジュールは並行chanを使用し、読み取り側と書き込み側に分割されています。多形チャネル「joins」をサポートするために、タイプシノニムが関連付けられた特別なクラスを使用します。

{-# LANGUAGE TypeFamilies #-}

class Sources s where
    type Joined s
    newJoinedChan :: IO (s, Messages (Joined s)) -- NOT EXPORTED

--output and input sides of channel:
data Messages a  -- NOT EXPORTED
data Mailbox a

instance Sources (Mailbox a) where
    type Joined (Mailbox a) = a
    newJoinedChan = undefined

instance (Sources a, Sources b)=> Sources (a,b) where
    type Joined (a,b) = (Joined a, Joined b)
    newJoinedChan = undefined

-- and so on for tuples of 3,4,5...

上記のコードを使用すると、次のようなことができます。

example = do
    (mb ,        msgsA) <- newJoinedChan
    ((mb1, mb2), msgsB) <- newJoinedChan
    --say that: msgsA, msgsB :: Messages (Int,Int)
    --and:      mb :: Mailbox (Int,Int)
    --          mb1,mb2 :: Mailbox Int

Behaviorチャネルの「読み取り」端から引き出したメッセージに対して実行できる、と呼ばれる再帰アクションがあります。

newtype Behavior a = Behavior (a -> IO (Behavior a))
runBehaviorOn :: Behavior a -> Messages a -> IO ()  -- NOT EXPORTED

これにより、またはBehavior (Int,Int)のいずれかでを実行できるようになります。2番目のケースでは、受け取るタプルの両方が実際には別々のesを経由していました。msgsAmsgsBIntMailbox

spawnこれはすべて、公開された関数でユーザーのために結び付けられています

spawn :: (Sources s) => Behavior (Joined s) -> IO s

...とを呼び出しnewJoinedChanrunBehaviorOn入力を返しますSources

やりたいこと

Behaviorユーザーが(タプルだけでなく)任意の製品タイプを作成できるようにしたいので、たとえば、上記Behavior (Pair Int Int)の例でを実行できますMessagesGHC.Generics多形性を維持しながらこれを実行したいのですが、Sourcesうまく機能させることができません。

spawn :: (Sources s, Generic (Joined s), Rep (Joined s) ~ ??) => Behavior (Joined s) -> IO s

APIで実際に公開される上記の例の部分はfstnewJoinedChanアクションのとBehaviorsであるため、許容可能なソリューションでは、の1つまたはすべてrunBehaviorOnまたはのsndを変更できnewJoinedChanます。

また、上記のAPIを拡張して、合計(まだ実装されていない)をサポートするようにするBehavior (Either a b)ので、GHC.Genericsが機能することを期待していました。

質問

  1. 上記のAPIを拡張して任意のAPIをサポートする方法はありGeneric a=> Behavior aますか?

  2. GHCのジェネリックスを使用していない場合、エンドユーザーの苦痛を最小限に抑えて必要なAPIを取得する他の方法はありますか(つまり、型に派生句を追加するだけです)?例:Data.Data

4

1 に答える 1

4

たぶん、このようなものですか?

{-# LANGUAGE TypeFamilies, DeriveGeneric, DefaultSignatures, TypeOperators, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}

import Control.Arrow
import GHC.Generics

class Sources s where
    type Joined s
    newJoinedChan :: IO (s, Messages (Joined s)) -- NOT EXPORTED
    default newJoinedChan :: (Generic s, SourcesG (Rep s)) => IO (s, Messages (JoinedG (Rep s)))
    newJoinedChan = fmap (first to) newJoinedChanG

class SourcesG g where
    type JoinedG g
    newJoinedChanG :: IO (g a, Messages (JoinedG g))

--output and input sides of channel:
data Messages a  -- NOT EXPORTED
data Mailbox a

instance Sources (Mailbox a) where
    type Joined (Mailbox a) = a
    newJoinedChan = undefined

instance (Sources a, Sources b)=> Sources (a,b) where
    type Joined (a,b) = (Joined a, Joined b)
    newJoinedChan = undefined

instance (SourcesG a, SourcesG b) => SourcesG (a :*: b) where
    type JoinedG (a :*: b) = (JoinedG a, JoinedG b)
    newJoinedChanG = undefined

instance (SourcesG a, Datatype c) => SourcesG (M1 D c a) where
    type JoinedG (M1 D c a) = JoinedG a
    newJoinedChanG = fmap (first M1) newJoinedChanG

instance (SourcesG a, Constructor c) => SourcesG (M1 C c a) where
    type JoinedG (M1 C c a) = JoinedG a
    newJoinedChanG = fmap (first M1) newJoinedChanG

instance (SourcesG a, Selector c) => SourcesG (M1 S c a) where
    type JoinedG (M1 S c a) = JoinedG a
    newJoinedChanG = fmap (first M1) newJoinedChanG

instance Sources s => SourcesG (K1 i s) where
    type JoinedG (K1 i s) = Joined s
    newJoinedChanG = fmap (first K1) newJoinedChan

newtype Behavior a = Behavior (a -> IO (Behavior a))

runBehaviorOn :: Behavior a -> Messages a -> IO ()
runBehaviorOn = undefined

spawn :: (Sources s) => Behavior (Joined s) -> IO s
spawn = undefined

data Pair a b = Pair a b deriving (Generic)

instance (Sources a, Sources b) => Sources (Pair a b) where
    type Joined (Pair a b) = JoinedG (Rep (Pair a b))
于 2013-01-17T12:05:29.687 に答える