如何理解这两个随机函数的组合?

时间:2016-04-15 08:35:30

标签: haskell monads

我正在学习Haskell,目前在Monads here上阅读Dan Piponi的博客。他的前两个例子对我来说非常有意义。但是我无法理解第三个例子,他编写了两个随机函数fg

f :: a -> StdGen -> (b,StdGen)
g :: a -> StdGen -> (b,StdGen)

我的理解是,g的返回类型为(b,StdGen),但f分别带有aStdGen类型的两个参数,因此{{1} }不能与f合成。但是,如果我们打开g返回的元组并将f x类型的第二个成员提供给g,则部分应用的版本g可以与StdGen合并。

所以,我认为函数f x应该使用函数bind

f x

并返回一个函数 f x :: StdGen -> (b,StdGen) ,其输入类型与f'的返回类型相同,即g

(b,StdGen)

Bind应该看起来像:

f' :: (b,StdGen) -> (b,StdGen)

但丹将bind :: (StdGen -> (b,StdGen)) -> ((b,StdGen) -> (b,StdGen)) 定义为:

bind

从该帖子的评论来看,很明显其他许多人最初都无法遵循丹的推理路线。 Dan也提供了一个示例,但函数bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (StdGen → (b,StdGen)) 不使用不同类型addDigita,而是使用常见类型b

有人可以描述Dan试图撰写的函数类型以及他如何使用他正在使用的Int类型吗?

1 个答案:

答案 0 :(得分:4)

不应将f视为返回(b, StdGen)的双参数函数,而应将f视为返回StdGen -> (b, StdGen)的单参数函数。因此,将整个类型 StdGen -> (b, StdGen)视为单个块/实体。如果有帮助,请为自己定义一个类型别名:

type Randomized a = StdGen -> (a, StdGen)

现在我们可以写

bind :: (a -> Randomized b) -> (Randomized a -> Randomized b)

并尝试实施它。这种类型遵循先前bind类型的模式:我们采用一个函数,它接受一个正常的东西并返回一个装饰的东西,然后把它变成一个函数,它接受并返回一个装饰的东西。 (但同样,装饰不只是与StdGen配对 - 装饰的东西本身就是一个功能。)

同样,第二个练习是实施

unit :: a -> Randomized a

再次遵循之前练习中设置的模式。