继续在教程中讨论,在A节中,更复杂的副作用:随机数,我得出如下结论:
bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (StdGen → (b,StdGen))
当“随机函数”(作者称之为“随机函数”)的类型如下:
a → StdGen -> (b,StdGen)
此外,绑定被定义为:
bind f x seed = let (x',seed') = x seed in f x' seed'
问:为什么绑定在签名的末尾有一个额外的StdGen
?应该是:
bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (b,StdGen)
我的理由如下:
f:: a -> StdGen -> (b,StdGen)
和"output“StdGen -> (a,StdGen)
。f
应用于a
和StdGen
,并返回f
签名所表示的任何内容--这就是(b, StdGen)
:
F:A -> StdGen -> (b,StdGen)f
也同时应用于值x'
和类型为StdGen
的seed'
,因此它的结果必须是元组!
将f种子= let ( x‘,seed') =x种子绑定在f x’种子‘中我哪里出错了?任何帮助都很感激!
注:对于未来的读者来说,作者对bind
的定义相当于标准定义,但参数翻转的除外:flip . >>=
发布于 2012-07-26 17:53:38
让我们来看看你的类型:
bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (b,StdGen)
现在,我完全赞同你的第一点:
Bind接受一个函数
f :: a -> StdGen -> (b,StdGen)
和"output“StdGen -> (a,StdGen)
。
但你的第二个让我担心:
它将
f
应用于a
和StdGen
。
您从哪里得到a
类型的值?您从哪里得到StdGen
类型的值?
这两个问题的答案都是“您没有一个在撒谎”;但是,由于您确实有一个StdGen -> (a,StdGen)
在撒谎,如果您有多一个StdGen
参数,您就可以得到这两个问题。这就是额外参数的来源。
现在,一个稍高层次的解释。问题的一部分(我认为)是,这些类型的签名有点杂乱无章,无法轻松阅读。我们需要一些抽象概念。我们试图在这里建模的是概率分布,我们把它建模为它们的抽样函数。因此,我们可以说a
上的发行版是一个知道如何从发行版中取样并返回a
的函数。
type Dist a = StdGen -> (a, StdGen)
现在,并不是所有的发行版都像这些一样平坦。例如,Bernoulli分布是“某种程度上的”Dist Bool
,但它也是参数化的选择False
的概率。我们可以这样写它的类型:
bernoulli :: Double -> Dist Bool
因此,我们可以将参数化分布建模为返回分布的函数;等效地,我们可以将返回分布的函数看作参数化分布。
现在,考虑到这种高级别的解释,bind
的类型变得更加可读性:
bind :: (a -> Dist b) -> (Dist a -> Dist b)
这说明bind
是一个函数,它告诉我们如何首先从a
发行版中取样,然后在从b
分发版取样时使用该a
作为参数。不仅如此,使用这个类型别名,为bind
编写一个没有“额外”参数的类型几乎是不可想象的。
https://stackoverflow.com/questions/11674516
复制相似问题