我正在使用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
的{{3}}为:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
那么,在Functor
的定义中,我是否必须以某种方式满足exampleFunc
条件?如果是这样,怎么样?我没有看到我的类型签名在哪里,我有机会宣布这个约束。或者我可能走错了路,我的问题与Functor
约束无关。
我已经阅读了有关“非法多态等”错误消息的所有Stack Overflow问题。也许这是我对Haskell缺乏熟悉的表现,但我看不出任何这些问题适用于我目前的情况。
我也无法找到有关错误消息通常含义的任何文档。
答案 0 :(得分:9)
镜头使用等级2类型并且您将它放在箭头的左侧,因此要使用任何类型的镜头类型,您必须使其合法甚至可以说出类似的内容
(forall a. foo) -> bar
你可以使用
{-# LANGUAGE RankNTypes #-} -- Rank2Types is a synonym for RankNTypes
位于文件顶部。没有它,即使使用镜头类型的同义词也是违法的,因为它们使用了你必须启用的语言的一部分。
答案 1 :(得分:7)
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
的参数函数。此功能requires the RankNTypes extension。
当forall
范围超过整个签名时(如隔离定义Lens
时),则不需要RankNTypes
。这个样子:
{-# LANGUAGE ExplicitForAll #-}
typechecks :: forall a. (a -> Int) -> Int
typechecks = undefined
但是这个函数与前一个函数不同,因为这里是调用者选择a
的类型。他可以传递一个仅适用于特定a
的参数函数。
exampleFunc'
有效,因为当没有指定forall
时,每个变量都有隐式foralls
,范围在整个签名上。
This explanation可能很有用。