2015-10-07 4 views
6

私は現在、反応性バナナを使用してFRPを学習しており、ランダム関数のストリームを作成したいと考えていました。私はこれを作ってみた:多相関数のイベントストリームを作成できますか?はいの場合、どうですか?

-- | take number generator, and some pulse event stream, generate random function stream 
mkRandom :: (Random a,RandomGen g) => g -> Event t b -> Event t ((a,a) -> a) 
mkRandom rng es = (\f -> \r -> fst $ f r) <$> (accumE first $ next <$> es) 
    where first = flip randomR rng 
     next _ prev range = randomR range g 
      where (a,g) = prev range 

動作しているようですが、私はこのようにそれを使用することができます:私はの番号を生成し、そのストリームを共有しようとすると、

randFuncs = mkRandom rnd (pulse 1000 time) 
some = ($ (0,10::Int)) <$> randFuncs 

しかし、当然のことながら別のタイプ:

some2 = ($ (0,10::Double)) <$> randFuncs 

タイプチェッカーは私が理解しています。その後、私は次のように関数を一般化しようとした:

mkRandom :: (RandomGen g) => g -> Event t b -> Event t (forall a. Random a => (a,a) -> a) 

その後、GHCは違法多型署名について、私はImpredicativeTypesを有効にしたいかどうかを訴えました。私はそれを行い、それを動作させるためにすべての注釈をつけようとしばらくしていましたが、GHCは常に型にマッチできないと訴えました。

私の質問は - 私がしたいことは可能ですか?そのためにImpredicativeTypesが本当に必要なのですか、それとも間違っていますか?

私はRankNTypesで十分だと思っていましたが、まだそのような拡張機能の経験はありません。

ありがとうございます!

EDIT:レコードの

、今役に立つ応答に基づいて、私の解決策は次のとおりです。

newtype RandomSource = Rand { getRand :: forall a. (Random a) => (a,a) -> [a] } 

-- | take number generator and some pulse event stream, generate randomness stream 
mkRandom :: RandomGen g => g -> Event t a -> Behavior t RandomSource 
mkRandom rng es = fst <$> (accumB (next id (id,rng)) $ next <$> es) 
    where next _ (_,rng) = (Rand $ flip randomRs g1, g2) 
      where (g1,g2) = split rng 

-- | take a rand. source, a range and a pulse, return stream of infinite lists of random numbers 
randStream :: Random a => Behavior t RandomSource -> (a,a) -> Event t b -> Event t [a] 
randStream funcs range pulse = ($ range) . getRand <$> funcs <@ pulse 
+1

「RankNTypes」(いくつかのシナリオでは?)を必要としないなど、簡単で実質的な方法で型を単純化するために、banana 1.0(現在の 'master')が反応すると言われています。試してみる。 –

+1

@ErikAllik反応バナナ1のAPIが変更されました。0は主に型パラメータ 't'に関係します。手元の問題はこれとは無関係です。 –

答えて

7

ImpredicativeTypesは本当にサポートまたは維持ので壊し続けるされていない非常に脆い拡張でありますさらに新しいGHCのバージョンで。これは、明示的にラップとnewtypeのコンストラクタをアンラップする必要があります

newtype PolyRandFun = PR { getPR :: forall a. Random a => (a,a) -> a) } 

、それ以外の場合、このような多型の機能を中心に通すために正常に動作します:

Aはるかに優れた作業オプションがnewtypeラッパーと一緒にRankNTypesを使用することです。

残念ながら、私はこの場合別の問題を予期しています。異なるRandom aインスタンスは、ランダム生成器異なる量を使用します。 IntegerInteger結果を構築するために生成されたプリミティブ乱数の量は、範囲のサイズによっても異なります。したがって実際に関数を呼び出すときに使用される型と範囲を知らなくても、次のgを取得することはできません。

幸運にも、 APIには、これを回避できる関数があります。splitは、本当に完全に独立した複数の乱数値を実際に生成する必要がある場合に、サブ計算に渡すことができる新しい乱数ジェネレータを提供します。

+1

ああ、私は「ImpredicativeTypes」が非常に脆いことを確認することができますが、それはほとんど維持されていると言えますか?私はそれが "RankN'へのむしろ自然な拡張であるべきだと感じています。 – leftaroundabout

+2

@leftaroundabout [Simon PJによる説明](https://mail.haskell.org/pipermail/glasgow-haskell-users/2014-February/024684.html) –

+2

@leftaroundについて、私は個人的にはできませんが、私の印象は"深い"問題。 GHCのタイプチェッカーは明らかに基本的に正しいことをすることができません。正しいタイプのチェッカーを作成する方法を誰も知らず、他のすべてのものを提供し、人が読めるエラーメッセージを漠然と表示します。 – dfeuer

関連する問題