重现 Haskell 镜头教程的问题

issues reproducing Haskell lens tutorial

我觉得我做错了什么,因为我什至无法重现 Haskell 的 lens tutorial:

> import Control.Lens
> data Point = Point { _x :: Double, _y :: Double } deriving (Show)
> data Atom = Atom { _element :: String, _point :: Point } deriving (Show)
> point = lens _point (\atom newPoint -> atom { _point = newPoint })
> :t point
point :: Functor f => (Point -> f Point) -> Atom -> f Atom
> point :: Lens' Atom Point = lens _point (\atom newPoint -> atom { _point = newPoint })

<interactive>:6:10: error:
    • Illegal polymorphic type: Lens' Atom Point
      Perhaps you intended to use RankNTypes or Rank2Types
    • In a pattern type signature: Lens' Atom Point
      In the pattern: point :: Lens' Atom Point
      In a pattern binding:
        point :: Lens' Atom Point
          = lens _point (\ atom newPoint -> atom {_point = newPoint})
> :set -XRankNTypes
> point :: Lens' Atom Point = lens _point (\atom newPoint -> atom { _point = newPoint })

<interactive>:8:29: error:
    • Couldn't match type ‘(Point -> f0 Point) -> Atom -> f0 Atom’
                     with ‘forall (f :: * -> *).
                           Functor f =>
                           (Point -> f Point) -> Atom -> f Atom’
      Expected type: Lens' Atom Point
        Actual type: (Point -> f0 Point) -> Atom -> f0 Atom
    • In the expression:
        lens _point (\ atom newPoint -> atom {_point = newPoint})
      In a pattern binding:
        point :: Lens' Atom Point
          = lens _point (\ atom newPoint -> atom {_point = newPoint})

f0Functor f 之间似乎确实存在一些差异。

不过,我这里的代码与教程中的代码没有什么不同,也没有多少 据我所知,扩展程序似乎在拯救我。

有人能指点一下吗?

我在评论中证实了猜测。这是因为您将类型放在模式匹配中。它可能是一个微不足道的模式匹配,但它确实是一个模式匹配,因为它在 =.

的 LHS 上绑定了一个名称

Haskell 默认情况下甚至不允许这样做。在 GHC 中,您需要启用 ScopedTypeVariables 扩展才能被允许。当你这样做时,它会对多态性产生奇怪的影响。我不了解该功能与高级多态性之间的所有交互,但它肯定是单态化一个类型,并且还期望它是多态的。那是行不通的。

我强烈建议您仅在将类型本身的名称与值绑定在一起时才将类型放入模式中。有时在处理存在主义时会出现这种情况,但我从未见过它出现在任何其他情况下。

否则,只需使用普通的类型归属语法,即使您必须输入几个分号才能使其在 ghci 中工作:

point :: Lens' Atom Point ; point = lens _point (\atom newPoint -> atom { _point = newPoint })