在镜头中观看和使用有什么区别?

What's the difference between view and use in lens?

有什么区别

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

use :: MonadState s m => Getting a s a -> m a

Control.Lens.Getter?

看一下类型签名,view 取一个 MonadReader(比如 ReaderT),use 取一个 MonadState(比如StateT)。现在,viewuse 都具有相同的 objective:从我们正在查看的事物中提取合理的值。

MonadReader表示只读状态。我们可以使用 ask. MonadState represents read-write state, which can be retrieved with get 访问值。所以 viewuse 都查询给定 monad 的内部状态,但是 view 调用 askuse 调用 get。一般来说,只有一个会适用于你的情况。

查看这两个函数的源代码并不是特别有启发性,除非您已经了解镜头是如何实现的(如果您了解了,那么您可能会理解 view 和 [=13= 之间的区别) ]), 所以这是一个很好的例子,说明类型签名比代码本身更有启发性。

A lens getter 给了我们一个从源到目标的函数:

(^.) :: s -> Getting a s a -> a

flip (^.) :: Getting a s a -> s -> a

任何函数都可以做成MonadReader计算,函数的参数类型作为环境类型:

asks :: MonadReader s m => (s -> a) -> m a

既然如此,(^.) 可以推广到 MonadReaderasks 之间的任何一个,从而产生 view:

view :: MonadReader s m => Getting a s a -> m a
view g = asks (\s -> s ^. g)

(我在这里使用的定义与您在 the Control.Lens.Getter source 中找到的字面意思不同,但就结果而言它们是等价的。)

同理,任何函数都可以做成MonadState状态不变的计算,函数的参数类型为状态类型:

gets :: MonadState s m => (s -> a) -> m a

因此,(^.) 也可以推广到 MonadStategets,结果是 use:

use :: MonadReader s m => Getting a s a -> m a
use g = gets (\s -> s ^. g)

从另一个角度看,viewuse分别可以看作是asksgets的变体,以getter为参数,而不是直接一个函数。

关于 view 的最后一点说明,函数本身是 MonadReader 的实例。既然如此,view 可以用作 (^.).

的 prefix/non-operator 版本