我正在和我一起工作 Control.Lens
。我写的实际功能相当复杂,但出于这个问题的目的,我把它归结为一个最小的失败例子:
import Control.Lens
exampleFunc :: Lens s t a b -> String
exampleFunc _ = "Example"
这无法编译,产生以下错误消息:
Illegal polymorphic or qualified type: Lens s t a b
Perhaps you intended to use -XRankNTypes or -XRank2Types
In the type signature for `exampleFunc':
exampleFunc :: Lens s t a b -> String
为什么这是非法的?它看起来非常类似于以下内容 不 编译:
import Data.Maybe
exampleFunc' :: Maybe (s, t, a, b) -> String
exampleFunc' _ = "Example"
所以我假设差异在于定义 Lens
。但是呢 Lens
打字 exampleFunc
的类型是非法的?我有一种潜在的怀疑,它与它有关 Functor
资格定义 Lens
,但我可能是错的。供参考, 定义 的 Lens
是:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
所以,我必须以某种方式满足 Functor
在我的定义中的资格 exampleFunc
?如果是这样,怎么样?我没有看到我的类型签名中的哪个位置我有机会声明这个约束。或者我可能走错了路,我的问题与我的问题无关 Functor
约束。
我已经阅读了有关“非法多态等”错误消息的所有Stack Overflow问题。也许这是我对Haskell缺乏熟悉的表现,但我看不出任何这些问题适用于我目前的情况。
我也没能找到任何关于错误信息通常意味着什么的文档。
镜头使用等级2类型,你可以在箭头左侧使用它,所以要使用任何类型的镜头类型你必须使它合法甚至说出类似的东西
(forall a. foo) -> bar
哪个你也可以
{-# LANGUAGE RankNTypes #-} -- Rank2Types is a synonym for RankNTypes
在文件的顶部。没有它,即使使用镜头类型同义词也是违法的,因为它们使用了您必须启用的语言的一部分。
exampleFunc
无法编译,因为 Lens
类型同义词是多态的,并且在签名中出现在所谓的“负位置”,也就是说,在左侧 ->
。
您可以使用 Lens
在一个类型签名甚至没有 RankNTypes
上。这个类型检查:
import Control.Lens
lensy :: Lens' (a,b) a
lensy = _1
但这没有成功:
oops :: Lens' (a,b) a -> Int
oops = const 5
为什么?出于同样的原因,如果没有这样做,也无法进行类型检查 RankNTypes
:
{-# LANGUAGE ExplicitForAll #-}
fails :: (forall a. a -> Int) -> Int
fails = undefined
在这里 forall
处于负面位置,并且范围仅在 a -> Int
。它是 履行 的 fails
而不是 呼叫者 的 fails
,选择类型的人 a
。调用者必须提供适用于所有人的参数函数 a
。此功能 需要RankNTypes扩展名。
当。。。的时候 forall
范围超过整个签名(如何 Lens
孤立地定义)没有必要 RankNTypes
。这个类型检查:
{-# LANGUAGE ExplicitForAll #-}
typechecks :: forall a. (a -> Int) -> Int
typechecks = undefined
但是这个功能与前一个功能不同,因为这里是 呼叫者 谁选择的类型 a
。他可以传递一个仅适用于特定的参数函数 a
。
exampleFunc'
工作是因为,当没有 forall
是指定的,有隐含的 foralls
对于每个变量,范围在整个签名上。
这个解释来自Haskell邮件列表可能很有用。