当一个函数出现在monad中时,它会发生一些变化。
GHCI:
> :t map
map :: (a -> b) -> [a] -> [b]
> a <- return map
> :t a
a :: (GHC.Prim.Any -> GHC.Prim.Any)
-> [GHC.Prim.Any] -> [GHC.Prim.Any]
此更改使得难以将函数存储在更高级别的类型中。
这里发生了什么,我可以让它不会发生吗?
(这也不违反monad法律之一吗?)
答案 0 :(得分:6)
首先,做a <- return map
之类的事情毫无意义 - 它与let a = map
相同,效果很好。那就是说,我认为这不是你的问题......
查看GHC.Prim.Any
的文档,它为我们提供了关于Any
角色的重要提示。
它还用于在类型之后实例化非约束类型变量 检查。例如,
length
具有类型length :: forall a. [a] -> Int
并且空列表的列表数据具有类型
[] :: forall a. [a]
为了将这两个词组成
length []
a 类型应用程序是必需的,但没有约束 选择。在这种情况下,GHC使用Any
(在类型应用程序语法方面,看起来像length @Any ([] @Any *)
)
问题在于,当GHCi看到x <- return map
时,它试图将其去除return map >>= \x -> ...
,但...
部分是您在GHCi中输入的任何内容。通常它会根据map
找出...
的类型变量将被实例化(或者它们是否应该被实例化为任何东西),但因为它没有任何内容。
@ sepp2k指出的另一个关键点是x
不能给出多态类型,因为(>>=)
期望(在其RHS上)排名为1的函数,这意味着它的论点不能是多态的。 (放松这个条件会直接进入RankNTypes
,此时你将失去可靠地推断类型的能力。)
因此,需要x
是单态的并且没有信息来帮助它实例化阻止x
单态的类型变量,它默认使用Any
。这意味着您获得(a -> b) -> [a] -> [b]
而不是(Any -> Any) -> [Any] -> [Any]
。