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

How to make sense of composing these two randomized functions?

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

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

我的理解是 g 的 return 类型是 (b,StdGen)f 有两个参数类型 aStdGen因此 f 不能与 g 组成。但是,如果我们解开由 g 编辑的元组 return 并将类型 StdGen 的第二个成员提供给f x

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

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

和return一个函数f',其输入类型与g的return类型相同,即(b,StdGen):

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

绑定应该如下所示:

bind :: (StdGen -> (b,StdGen)) -> ((b,StdGen) -> (b,StdGen))

但 Dan 将 bind 定义为:

bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (StdGen → (b,StdGen))

从关于 post 的评论可以看出,许多其他人最初无法理解 Dan 的推理思路。 Dan 也给出了一个例子,但是函数 addDigit 并没有使用不同的类型 ab 而是一个普通的类型 Int.

有人可以描述一下 Dan 试图编写的函数类型是什么以及他是如何得出他正在使用的 bind 类型的吗?

与其将 f 视为 returns 和 (b, StdGen) 的双参数函数,不如将 f 视为 [=33] 的单参数函数=]一个StdGen -> (b, StdGen)。因此,将 整个类型 StdGen -> (b, StdGen) 视为单个 chunk/entity。如果有帮助,请为自己定义一个类型别名:

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

现在我们可以写了

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

并尝试实现它。这种类型遵循前面 bind 类型的模式:我们将一个接受普通事物和 returns 装饰事物的函数,并将其变成一个既接受又接受 returns 的函数装饰的东西。 (但同样,装饰不仅仅是与 StdGen 配对——装饰的东西本身就是一个函数。)

同样,第二个练习将是实施

unit :: a -> Randomized a

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