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
放入monadma
joinM
从monadma
所以
joinM
应该真正适用于任何monad,也就是说,不一定是嵌套的monad,比如M(ma)
,对吧?monad的要点是你不能从它们中得到值。如果join
hadtypema->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
hadtypema->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
实现的,它具有