首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建多态函数的事件流-可能吗?如果是,怎么做?

创建多态函数的事件流-可能吗?如果是,怎么做?
EN

Stack Overflow用户
提问于 2015-10-07 13:55:19
回答 1查看 91关注 0票数 6

我目前正在学习活性香蕉玻璃钢,并希望创建一个随机函数流。我想出了这个:

代码语言:javascript
复制
-- | 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

它似乎很管用,我可以这样用它:

代码语言:javascript
复制
randFuncs = mkRandom rnd (pulse 1000 time)
some = ($ (0,10::Int)) <$> randFuncs

但是,当然,当我尝试共享该流以生成不同类型的数字时:

代码语言:javascript
复制
some2 = ($ (0,10::Double)) <$> randFuncs

类型检查程序抱怨,我理解。然后,我尝试将该函数概括为以下内容:

代码语言:javascript
复制
mkRandom :: (RandomGen g) => g -> Event t b -> Event t (forall a. Random a => (a,a) -> a)

然后,GHC抱怨非法的多态签名以及我是否愿意启用ImpredicativeTypes。我做了很长一段时间,试图注释所有东西,使其工作,但GHC总是抱怨说,它不能匹配的类型。

我的问题是-能不能做我想做的事?我真的需要ImpredicativeTypes吗?还是我做错了?

我认为RankNTypes应该足够了,但是我还没有这样的扩展经验。

提前感谢!

编辑:

为了记录在案,现在我基于有帮助的响应的解决方案是:

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-07 14:27:52

ImpredicativeTypes是一个非常脆弱的扩展,不受真正的支持或维护,因此在新的GHC版本中不断发展。

一个更好的工作方法是将RankNTypesnewtype包装器一起使用:

代码语言:javascript
复制
newtype PolyRandFun = PR { getPR :: forall a. Random a => (a,a) -> a) }

这要求您显式地包装和展开newtype构造函数,但是对于传递这样的多态函数来说,这样的构造函数可以很好地工作。

不幸的是,我预见到了这种情况下的另一个问题。不同的Random a实例使用它们的随机生成器的数量不同,在例如Integer的情况下,生成构建Integer结果的原始随机数的数量甚至将取决于范围的大小。因此,如果不知道在实际调用函数时使用的类型和范围,就无法获得下一个g

幸运的是,System.Random API中有一个函数可以解决这个问题:split为您提供了一个新的随机生成器,当您确实需要完全独立地生成多个随机值时,该生成器可以传递到子计算中。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32994152

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档