Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
haskell-连接函数的类型_Haskell_Monads - Fatal编程技术网

haskell-连接函数的类型

haskell-连接函数的类型,haskell,monads,Haskell,Monads,请注意,joinM(m0)将无法进行类型检查,而joinM'(m0)则可以 我的问题是:joinM为什么被定义为M(ma)->ma,而不是ma->a 据我了解, unitM将值a放入monadma joinM从monadma 所以joinM应该真正适用于任何monad,也就是说,不一定是嵌套的monad,比如M(ma),对吧?monad的要点是你不能从它们中得到值。如果joinhadtypema->a,那么IOmonad将毫无用处,因为您可以自由提取值。monad的要点是,您可以将计算链接在一起

请注意,
joinM(m0)
将无法进行类型检查,而
joinM'(m0)
则可以

我的问题是:
joinM
为什么被定义为
M(ma)->ma
,而不是
ma->a

据我了解,
unitM
将值
a
放入monad
ma

joinM
从monad
ma


所以
joinM
应该真正适用于任何monad,也就是说,不一定是嵌套的monad,比如
M(ma)
,对吧?

monad的要点是你不能从它们中得到值。如果
join
hadtype
ma->a
,那么
IO
monad将毫无用处,因为您可以自由提取值。monad的要点是,您可以将计算链接在一起(
>=
可以定义为
连接
,前提是您有
返回
fmap
)并将值放入一元上下文中,但您(通常)无法将它们取出

在您的具体案例中,您已经定义了什么本质上是标识单子。在这种情况下,很容易提取值;你只需剥去
M
的一层,继续你的生活。但对于一般的单子来说,情况并非如此,因此我们限制了
join
的类型,以便可以使用更多的单子

顺便说一下,您的
bindM
类型不正确。
>>=
的一般类型为

data M a = M a deriving (Show)
unitM a = M a
bindM (M a) f = f a

joinM :: M (M a) -> M a
joinM m = m `bindM` id

joinM' :: M a -> a
joinM' m = m `bindM` id
您的函数具有类型

(>>=) :: Monad m => m a -> (a -> m b) -> m b

请注意,您的类型更一般。因此,同样,在您的特定情况下,您可以避免对
joinM
的要求过于宽松,而特定的monad则不能。试着给
bindM
一个显式类型签名
ma->(a->mb)->mb
,然后看看你的两个连接函数是否仍在进行类型检查。

monad的要点是你不能从它们中得到值。如果
join
hadtype
ma->a
,那么
IO
monad将毫无用处,因为您可以自由提取值。monad的要点是,您可以将计算链接在一起(
>=
可以定义为
连接
,前提是您有
返回
fmap
)并将值放入一元上下文中,但您(通常)无法将它们取出

在您的具体案例中,您已经定义了什么本质上是标识单子。在这种情况下,很容易提取值;你只需剥去
M
的一层,继续你的生活。但对于一般的单子来说,情况并非如此,因此我们限制了
join
的类型,以便可以使用更多的单子

顺便说一下,您的
bindM
类型不正确。
>>=
的一般类型为

data M a = M a deriving (Show)
unitM a = M a
bindM (M a) f = f a

joinM :: M (M a) -> M a
joinM m = m `bindM` id

joinM' :: M a -> a
joinM' m = m `bindM` id
您的函数具有类型

(>>=) :: Monad m => m a -> (a -> m b) -> m b

请注意,您的类型更一般。因此,同样,在您的特定情况下,您可以避免对
joinM
的要求过于宽松,而特定的monad则不能。尝试给出<代码> BIDM一个显式类型签名:代码> m A- >(A->M B)-> M B<代码>,然后查看两个连接函数仍然是TyChuto.

< P>给定类型构造函数<代码>::*> *>代码>和类型<代码> A <代码>,请考虑以下类型的序列

bindM :: M a -> (a -> b) -> b
如果我们有多态函数
return::b->mb
extract::mb->b
(您的选择
join
),我们可以将上述任何类型的值转换为上述任何其他类型。实际上,我们可以根据需要使用这两个函数添加和删除
M
,适当地选择
b
类型。更随意地说,我们可以在这样的类型序列中同时向右和向左移动

相反,在monad中,我们可以不受限制地向右移动(使用
return
)。我们几乎可以在任何地方向左移动:重要的例外是我们不能从
ma
移动到
a
。这是通过
join::M(mc)->mc
实现的,其类型
extract::mb->b
仅限于
b=mc
的情况。因此,从本质上讲,我们可以向左移动(如
提取
),但只有当我们最终得到一个至少有一个
M
的类型时,才可以向左移动——因此,只需
ma

正如Carl在上面的评论中提到的,这种限制使更多的单子成为可能。例如,如果
M=[]
是列表单子,我们可以正确地实现
return
join
而不是
extract

a, M a, M (M a), M (M (M a)), ...

相反,
extract::[a]->a
不能是一个total函数,因为
extract[]::a
将是一个良好的类型,但会尝试从空列表中提取类型为
a
的值。众所周知的理论结果是,任何总表达式都不能具有多态类型
…:a
。我们可以有< <代码> >:<代码> >代码> >:<代码> >或“代码>头[]::A/CODE >,但所有这些都不完全,并且在评估时会引发错误。

< P>给定类型构造函数<代码>::*> *>代码>,类型<代码> A <代码>,请考虑以下类型的序列

bindM :: M a -> (a -> b) -> b
如果我们有多态函数
return::b->mb
extract::mb->b
(您的选择
join
),我们可以将上述任何类型的值转换为上述任何其他类型。实际上,我们可以根据需要使用这两个函数添加和删除
M
,适当地选择
b
类型。更随意地说,我们可以在这样的类型序列中同时向右和向左移动

相反,在monad中,我们可以不受限制地向右移动(使用
return
)。我们几乎可以在任何地方向左移动:重要的例外是我们不能从
ma
移动到
a
。这是通过
join::M(mc)->mc
实现的,它具有