我正在浏览lens
tutorial,特别是试图绕过view
中涉及的类型。
所以,采取定义
data Atom = Atom { _element :: String, _point :: Point }
data Point = Point { _x :: Double, _y :: Double }
makeLenses ''Atom
makeLenses ''Point
让我们检查表达式view (point . x)
的类型:
*Main> :t view (point . x)
view (point . x) :: MonadReader Atom m => m Double
因此,给定一个Atom
的环境,我们可以生成一个Double
包裹在MonadReader
中。很好,这比镜头新手所期望的更为通用!
现在,让我们尝试将其应用于某些atom
:
*Main> :t view (point . x) (Atom "C" (Point 1 2))
view (point . x) (Atom "C" (Point 1 2)) :: Double
这种类型检查如何给出view (point . x)
的上述类型?我知道部分应用的函数类型MonadReader
有一个r ->
的实例,但ghc如何能够确定在这种情况下应该使用这个特定的实例(如果那样的话)当然,确实使用了一个吗?
答案 0 :(得分:4)
关键是您使用了 application 的语法。
写作时
view (point . x) (Atom "C" (Point 1 2))
您实际上是在f a
和f = view (point . x)
编写应用a = Atom "C" (Point 1 2)
。要键入check f a
GHC最初从
f :: t1 -> t2 -- in prefix for rm, this is written as (->) t1 t2
a :: t1
对于一些新的类型变量t1, t2
。这始终适用于所有应用程序。
(好吧,差不多。一些高级类型需要更仔细的算法,但我忽略了这一点。)
然而,GHC也知道
f :: MonadReader Atom m => m Double
a :: Atom
因此它推断出t1 ~ Atom
和m ~ (->) t1 ~ (->) Atom
。由于这确实是一个MonadRead Atom
实例,因此它继续进行。