10

我一直在研究本文中给出的用于创建镜头的示例。

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

4

2 回答 2

11

这是正常的事情。该lens库严重依赖于多态性,因此单态性限制(这使得事物的多态性低于其应有的水平)并不能很好地与之交互。在您的情况下,我认为您也可以这样编写代码:

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

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

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

Lens' Meetup Latitude定义Lens Meetup Meetup Latitude Latitude。_

并且Lens Meetup Meetup Latitude Latitude定义forall f. Functor f => (Meetup -> f Meetup) -> Latitude -> f Latitude

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

于 2014-04-14T17:35:46.223 回答
4

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

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

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

于 2014-04-14T17:15:38.880 回答