11

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

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

4

2 回答 2

9

镜头使用 2 级类型,并且您将其放在箭头的左侧,因此要使用任何这样的镜头类型,您必须使其合法,甚至可以说出类似的话

(forall a. foo) -> bar

你也可以

{-# LANGUAGE RankNTypes #-} -- Rank2Types is a synonym for RankNTypes

在文件的顶部。没有它,即使使用镜头类型同义词也是非法的,因为它们使用您必须启用的语言的一部分。

于 2013-11-20T19:43:42.340 回答
7

exampleFunc无法编译,因为Lens类型同义词是多态的,并且出现在签名中所谓的“负位置”,即->.

Lens即使没有on,您也可以在类型签名中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而不是 的调用者。调用者必须提供一个适用于所有. 此功能需要 RankNTypes 扩展failsaa

forall整个签名的范围(如单独Lens定义时)时,不需要RankNTypes. 这种类型检查:

{-# LANGUAGE ExplicitForAll #-}

typechecks :: forall a. (a -> Int) -> Int
typechecks = undefined

但是这个函数和上一个函数不同,因为这里是调用者选择的类型a。他可以传递仅适用于特定的参数函数a

exampleFunc'之所以起作用,是因为,当forall指定 no 时,每个变量都有隐含foralls的,范围涵盖整个签名。

Haskell 邮件列表中的这个解释可能很有用。

于 2013-11-20T21:48:54.270 回答