为什么函数的类型在GHCi中出现monad时会发生变化

时间:2016-07-29 02:29:47

标签: haskell polymorphism ghc ghci

当一个函数出现在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法律之一吗?)

1 个答案:

答案 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]