[英]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
是一个函数,它:
rndf1
相同的参数类型 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
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'
在这个定义中, f
和x
都是函数(如果将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.