镜头中的视图和使用有啥区别?

Posted

技术标签:

【中文标题】镜头中的视图和使用有啥区别?【英文标题】:What's the difference between view and use in lens?镜头中的视图和使用有什么区别? 【发布时间】:2021-06-20 12:21:39 【问题描述】:

有什么区别

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

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

在Control.Lens.Getter?

【问题讨论】:

你了解MonadReaderMonadState的区别吗? 【参考方案1】:

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 可以用作(^.) 的前缀/非运算符版本。

【讨论】:

【参考方案2】:

查看类型签名,view 采用 MonadReader(例如 ReaderT),use 采用 MonadState(例如 StateT)。现在,viewuse 都有相同的目标:从我们正在查看的东西中提取合理的价值。

MonadReader 表示只读状态。我们可以使用ask 访问其中的值。 MonadState代表读写状态,可以用get检索。所以viewuse 都查询给定的monad 的内部状态,但是view 调用askuse 调用get。一般来说,只有一种适用于您的情况。

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

【讨论】:

“只有一个适用于你的情况”——我认为这忽略了一个关键点。如果只有一个适用,那么两者都没有意义。我们只会有更一般的view,以及ask,我们可以忘记use/get。 IMO,我们两者都有的原因是有可能有一个MonadReader s1,它也是MonadState s2(例如使用RWS),现在我们确实需要两个操作来“读取只读状态”和“读取读写状态”,因此有两个与镜头相关的操作。 假设我不喜欢 RWS 的设计模式,或者在没有某种区分标识的情况下将两个状态组合在同一个 monad 堆栈中,那么 MonadState 是否有意义是MonadReader的子类? 如果你不喜欢RWS 那么我想。但是我个人发现RWS 在很多情况下都非常有用,当我们有一些***配置环境(只读)和一些可变程序状态(读写)时,两者都没有办法共存,就像(正如您正确指出的那样)在使用 mtl 习语时,您不能轻易地将两个 MonadState 实例放在同一个堆栈中。 @AriFordsham 一个复杂的问题是MonadReader 也有local 作为一种方法,而localMonadState 中不合适。虽然原则上可以通过将MonadReader 分成两个类来避免这个问题,但 Silvio Mayolo 的反对意见仍然存在:能够在单个 monad 上分别处理固定环境和可变状态是有用的,并且子类关系将,就 mtl 而言,排除它。

以上是关于镜头中的视图和使用有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

相机镜头光学中的一些疑难问题的解释

模板-haskell中的单双引号/撇号有啥区别?

镜头调焦和对焦的区别

如何检验一支工业镜头的好坏?

ARKit 是不是考虑 iPhone 和 iPad 中的镜头失真?

如何在没有控件的情况下在 android 中制作相机应用程序,以便仅在屏幕上显示来自镜头的视图? [关闭]