rlk*_*024 11 haskell lenses haskell-lens
我正在和我一起工作Control.Lens
.我写的实际功能相当复杂,但为了这个问题的目的,我把它归结为一个最小的失败例子:
import Control.Lens
exampleFunc :: Lens s t a b -> String
exampleFunc _ = "Example"
Run Code Online (Sandbox Code Playgroud)
这无法编译,产生以下错误消息:
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
Run Code Online (Sandbox Code Playgroud)
为什么这是非法的?这似乎非常类似于以下,这确实编译:
import Data.Maybe
exampleFunc' :: Maybe (s, t, a, b) -> String
exampleFunc' _ = "Example"
Run Code Online (Sandbox Code Playgroud)
所以我假设差异在于定义Lens
.但是这种Lens
类型exampleFunc
的类型是非法的呢?我有一种潜在的怀疑,它与Functor
定义中的资格有关Lens
,但我可能是错的.作为参考,定义的Lens
是:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
Run Code Online (Sandbox Code Playgroud)
那么,我是否必须以某种方式满足Functor
我的定义中的资格exampleFunc
?如果是这样,怎么样?我没有看到我的类型签名在哪里,我有机会宣布这个约束.或者我可能在错误的轨道上,我的问题与Functor
约束无关.
我已经阅读了有关"非法多态等"错误消息的所有Stack Overflow问题.也许这是我对Haskell缺乏熟悉的表现,但我看不出任何这些问题适用于我目前的情况.
我也没能找到任何关于错误信息通常意味着什么的文档.
镜头使用等级2类型,你在箭头的左边有它,所以要使用这样的任何类型的镜头你必须使它合法甚至说出类似的东西
(forall a. foo) -> bar
Run Code Online (Sandbox Code Playgroud)
哪个你也可以
{-# LANGUAGE RankNTypes #-} -- Rank2Types is a synonym for RankNTypes
Run Code Online (Sandbox Code Playgroud)
在您的文件的顶部.没有它,即使使用镜头类型的同义词也是违法的,因为它们使用了您必须启用的语言的一部分.
exampleFunc
无法编译,因为Lens
类型同义词是多态的,并出现在所谓的"负位置"的签名中,也就是说,在左侧->
.
Lens
即使没有RankNTypes
打开,您也可以在类型签名中使用.这个类型检查:
import Control.Lens
lensy :: Lens' (a,b) a
lensy = _1
Run Code Online (Sandbox Code Playgroud)
但这没有成功:
oops :: Lens' (a,b) a -> Int
oops = const 5
Run Code Online (Sandbox Code Playgroud)
为什么?出于同样的原因,如果没有RankNTypes
:
{-# LANGUAGE ExplicitForAll #-}
fails :: (forall a. a -> Int) -> Int
fails = undefined
Run Code Online (Sandbox Code Playgroud)
这里forall
处于负面位置,范围仅在a -> Int
.这是实现的fails
,而不是调用者的fails
,谁选择的类型之一a
.调用者必须提供适用于所有人的参数函数a
.此功能需要RankNTypes扩展名.
当forall
整个签名上的范围(如何单独Lens
定义)时,则不需要RankNTypes
.这个类型检查:
{-# LANGUAGE ExplicitForAll #-}
typechecks :: forall a. (a -> Int) -> Int
typechecks = undefined
Run Code Online (Sandbox Code Playgroud)
但是这个功能与前一个功能不同,因为这里是调用者选择的类型a
.他可以传递一个仅适用于特定的参数函数a
.
exampleFunc'
因为,当没有forall
指定时,foralls
每个变量都有隐含的,覆盖整个签名.
来自Haskell邮件列表的这种解释可能很有用.