Control.Lens中的“非法多态或限定类型”

时间:2013-11-20 19:28:57

标签: haskell lenses lens

我正在使用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缺乏熟悉的表现,但我看不出任何这些问题适用于我目前的情况。

我也无法找到有关错误消息通常含义的任何文档。

2 个答案:

答案 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,范围在整个签名上。

来自Haskell邮件列表的

This explanation可能很有用。