繁体   English   中英

Haskell Monad绑定currying

[英]Haskell Monad bind currying

我目前需要一些大脑训练,并且在Haskell和Monads上找到了这篇文章

我在练习7 re时遇到麻烦。 随机函数绑定。

为了使问题更易于实验,我将StdGen类型替换为未指定的类型。 所以代替...

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

我用了...

bind :: (a -> c -> (b,c)) -> (c -> (a,c)) -> (c -> (b,c))

对于实际的功能实现(直接从练习开始)

bind f x seed = let (x',seed') = x seed 
                 in f x' seed'

还有2个随机函数可用于:

rndf1 :: (Num a, Num b) => a -> b -> (a,b)
rndf1 a s = (a+1,s+1)

rndf2 :: (Num a, Num b) => a -> b -> (a,b)
rndf2 a s = (a+8,s+2)

因此,在Haskell编译器(ghci)中使用此命令,我得到...

:t bind rndf2
bind rndf2 :: (Num a, Num c) => (c -> (a, c)) -> c -> (a, c)

这将匹配以rndf2作为第一个参数的绑定。

但是我不明白的是...

:t bind rndf2 . rndf1

突然给

bind rndf2 . rndf1 :: (Num a, Num c) => a -> c -> (a, c)

这是我们尝试制作的合成的正确类型,因为

bind rndf2 . rndf1

是一个函数,它:

  1. 采用与rndf1相同的参数类型
  2. AND将rndf1的返回rndf1作为管道,作为rndf2的输入,以返回与rndf2相同的类型

rndf1可以采用2个参数rndf2 a -> c并且rndf2返回(a, c)因此它与这些函数的组成应具有类型匹配:

bind rndf2 . rndf1 :: (Num a, Num c) => a -> c -> (a, c)

这与我最初想绑定的天真类型不匹配

bind f :: (a -> b -> (c, d)) -> (c, d) -> (e, f)

在这里,神话神话中的bind接受了一个带有两个参数的函数,并产生了一个接受元组的函数,以便可以将rndf1的输出馈送到rndf2

  1. 为什么绑定函数需要按原样编码
  2. 为什么bind函数没有朴素的类型

bind应具有两个功能。 您的“初始”类型签名使用一个函数和一个元组并生成一个元组。 这实际上不适用于此问题: rndf1不是元组,它是一个函数。 一旦将参数应用到它, rndf1 as就会变成元组。 因此, bind必须是一个具有两个功能的功能。

将元组传递到带有两个参数的函数中的神秘力量在于bind的定义。

bind :: (a -> c -> (b,c)) -> (c -> (a,c)) -> (c -> (b,c))
bind f x seed = let (x',seed') = x seed 
                 in f x' seed'

在这个定义中, fx都是函数(如果将x重命名为g也许会更清楚)。

let (x',seed') = x seed x seed产生一个元组。 在等号的左侧,该元组的各个元素被赋予新名称,然后在下一行将这些名称传递给函数f

因此,可能有助于分解表达式bind rndf2 . rndf1 bind rndf2 . rndf1

请记住,所有函数实际上只有一个参数。 rndf1的类型可以最准确地写为(Num a , Num b) => a -> (b -> (a,b)) 这对于理解接下来的内容非常有帮助。

另一有帮助的事情是考虑如何使用带有参数的表达式。 如:( (bind rndf2 . rndf1) as

由于所有函数都有一个参数,因此将它们一一发送到括号内。 首先: ((bind rndf2 . rndf1) a) s

现在,您可以不使用来重写表达式. 运算符:( (bind rndf2 (rndf1 a)) s a传递给rndf1是因为这样. 的工作原理:点右侧的函数接受输入,然后将其输出传递给左侧的函数。

你会看到的类型签名rndf1 a的第二个参数匹配bind 因此,然后应用参数rndf2(rndf1 a)进行bind

bind rndf2 (rndf1 a) seed = let (x', seed') = (rndf1 a) seed
                             in rndf2 x' seed'

现在,您可以在圆括号内使用一个仅包含一个seed参数的函数。 因此,您可以将s并将其应用于函数:

bind rndf2 (rndf1 a) s = let (x', seed') = (rndf1 a) s
                          in rndf2 x' seed'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM