Lens中view函数类型匹配疑问:MonadReader与函数实例推导
(-> 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
askoperation (which retrieves the environment) is justid—it returns the input argument directly. - The
askshelper (whichviewis built on) simplifies to\f -> f: it takes a function that extracts a value from the environment, and returns that exact function (since(-> r) ais just shorthand forr -> 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:
- The entire expression needs to produce a
Double, so applying your concreteAtomtoview (point . x)must result in that type. - If
view (point . x)has typem Double, then applying it to anAtommeansm Doublehas to be a function that accepts anAtom—i.e.,Atom -> Double. - GHC scans available
MonadReader Atom minstances and finds that(-> Atom)fits perfectly:(-> Atom) Doubleis exactlyAtom -> 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

