我一直在研究这个article中给出的用于创建镜头的示例。
我按照文章中的说明创建了Lens
,以下是我的代码:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
type Degrees = Double
type Latitude = Degrees
type Longitude = Degrees
data Meetup = Meetup { _name :: String, _location :: (Latitude, Longitude) }
makeLenses ''Meetup
meetupLat = location._1 :: Lens' Meetup Latitude
现在,除非我包含此代码,否则此代码不会进行类型检查:
{-# LANGUAGE NoMonomorphismRestriction #-}
但是文章中没有,我发现他们已经提到了 关于单态性限制。这是正常的事情还是我 在这做错了什么?
使用的编译器:GHC 7.6.2
答案 0 :(得分:11)
这是正常的事情。 lens
库在很大程度上依赖于多态性,因此单态限制(使得事物的多态性变得不那么多)与它的相互作用不是很好。在您的情况下,我认为您也可以像这样编写代码:
meetupLat :: Lens' Meetup Latitude
meetupLat = location._1
如果为绑定提供显式多态类型签名,则单态限制无关紧要。
请注意,Lens' Meetup Latitude
是多态类型,即使它看起来是单形的。类型变量隐藏在Lens'
类型同义词中。特别是:
Lens' Meetup Latitude
defined为Lens Meetup Meetup Latitude Latitude
。
Lens Meetup Meetup Latitude Latitude
defined为forall f. Functor f => (Meetup -> f Meetup) -> Latitude -> f Latitude
所以这就是f
。我认为单态限制会强制f
的具体实例化,但是你想保持它的多态性,因为镜头的不同用户会选择不同的f
。例如,view
将选择Const
,set
将选择Identity
。因此,保持f
多态性以允许镜头用户进行这些选择非常重要。
答案 1 :(得分:4)
您只需要在函数上指定类型而不是在其定义上
meetupLat :: Lens' Meetup Latitude
meetupLat = latitude._1
我认为这是因为幕后Lens'
的复杂类型意味着虽然它的定义具有该类型,但编译器仍然很难猜测meetupLat
具有相同的类型。也许对Monomorphism限制有更深入了解的人可以更好地阐述。