镜头和单态限制

时间:2014-04-14 17:08:58

标签: haskell lens

我一直在研究这个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

2 个答案:

答案 0 :(得分:11)

这是正常的事情。 lens库在很大程度上依赖于多态性,因此单态限制(使得事物的多态性变得不那么多)与它的相互作用不是很好。在您的情况下,我认为您也可以像这样编写代码:

meetupLat :: Lens' Meetup Latitude
meetupLat = location._1

如果为绑定提供显式多态类型签名,则单态限制无关紧要。

请注意,Lens' Meetup Latitude多态类型,即使它看起来是单形的。类型变量隐藏在Lens'类型同义词中。特别是:

Lens' Meetup Latitude definedLens Meetup Meetup Latitude Latitude

Lens Meetup Meetup Latitude Latitude definedforall f. Functor f => (Meetup -> f Meetup) -> Latitude -> f Latitude

所以这就是f。我认为单态限制会强制f的具体实例化,但是你想保持它的多态性,因为镜头的不同用户会选择不同的f。例如,view将选择Constset将选择Identity。因此,保持f多态性以允许镜头用户进行这些选择非常重要。

答案 1 :(得分:4)

您只需要在函数上指定类型而不是在其定义上

meetupLat :: Lens' Meetup Latitude
meetupLat = latitude._1

我认为这是因为幕后Lens'的复杂类型意味着虽然它的定义具有该类型,但编译器仍然很难猜测meetupLat具有相同的类型。也许对Monomorphism限制有更深入了解的人可以更好地阐述。