You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lens中view函数类型匹配疑问:MonadReader与函数实例推导

Understanding How GHC Picks the (-> s) MonadReader Instance for view

Great question! Let's walk through exactly what's happening here, step by step.

First, Recall the Type of view

The view function from Control.Lens has this general type:

view :: MonadReader s m => Getting a s a -> m a

With your lens point . x (which is a Lens' Atom Double), this means view (point . x) has the polymorphic type:

view (point . x) :: MonadReader Atom m => m Double

This is the flexible type you see when checking the expression without applying it to a concrete value.

What's the (-> s) MonadReader Instance?

You’re right that the function type r -> (written formally as (-> r)) is an instance of MonadReader. Here’s what that instance boils down to in practice:

  • For MonadReader r (-> r), the "environment" the reader monad uses is just the argument passed to the function.
  • The ask operation (which retrieves the environment) is just id—it returns the input argument directly.
  • The asks helper (which view is built on) simplifies to \f -> f: it takes a function that extracts a value from the environment, and returns that exact function (since (-> r) a is just shorthand for r -> a).

In short, when m is (-> Atom), m Double translates to Atom -> Double—a plain function that takes an Atom and spits out a Double.

How GHC Infers the Correct Instance

When you write:

view (point . x) (Atom "C" (Point 1 2))

GHC works backwards to resolve the polymorphic type. Here’s the play-by-play:

  1. The entire expression needs to produce a Double, so applying your concrete Atom to view (point . x) must result in that type.
  2. If view (point . x) has type m Double, then applying it to an Atom means m Double has to be a function that accepts an Atom—i.e., Atom -> Double.
  3. GHC scans available MonadReader Atom m instances and finds that (-> Atom) fits perfectly: (-> Atom) Double is exactly Atom -> Double.

Once GHC locks in this instance, view (point . x) becomes the getter function for your lens chain: it takes an Atom, traverses through point to get the nested Point, then grabs the Double from x. Applying it to your concrete Atom gives you the final Double result.

A Quick Validation

If you explicitly type view (point . x) as a function, GHC will confirm this instance is valid:

:t view (point . x)  -- Without argument: MonadReader Atom m => m Double
:t view (point . x) :: Atom -> Double  -- Explicit function type works seamlessly!

内容的提问来源于stack exchange,提问作者0xd34df00d

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:44:38