我和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的类型成为非法呢?我隐约怀疑它与Lens定义中的Functor资格有关,但我可能错了。值得借鉴的是,定义 of Lens是:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t那么,我是否必须在某种程度上满足Functor在exampleFunc定义中的限定?如果是这样的话,是怎么做的?我看不出在我的类型签名中我有机会声明这个约束。或者我走错了轨道,我的问题与Functor约束无关。
我已经阅读了关于“非法多态等”错误消息的所有堆栈溢出问题。也许这是因为我对Haskell缺乏了解,但我看不出其中任何一个问题都适用于我目前的情况。
我也没有找到任何关于错误信息的一般含义的文档。
发布于 2013-11-20 19:43:42
镜头使用等级2的类型,而你把它放在箭头的左边,所以要使用像这样的任何透镜类型,你必须使它成为合法的,甚至说出类似的东西。
(forall a. foo) -> bar你也可以用它
{-# LANGUAGE RankNTypes #-} -- Rank2Types is a synonym for RankNTypes在你档案的顶端。没有它,即使使用透镜类型的同义词也是违法的,因为它们使用的是你必须启用的语言的一部分。
发布于 2013-11-20 21:48:54
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的实现,而不是选择a类型的fails的调用者。调用方必须提供一个适用于所有a的参数函数。这个特性需要RankNTypes扩展。
当forall覆盖整个签名(比如Lens是孤立定义的)时,就不需要RankNTypes了。这种打字机:
{-# LANGUAGE ExplicitForAll #-}
typechecks :: forall a. (a -> Int) -> Int
typechecks = undefined但是这个函数不同于前一个函数,因为这里是调用者选择了a的类型。他可以传递一个仅适用于特定a的参数函数。
exampleFunc'之所以有效,是因为当没有指定forall时,每个变量都有隐式foralls,其范围涵盖整个签名。
来自Haskell邮件列表的这一解释可能是有用的。
https://stackoverflow.com/questions/20105147
复制相似问题