在Control.Lens.Lens
中,有一个功能
modifying :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
允许通过纯函数MonadState
转换(a -> b)
状态下的镜头下的值。
但是,我们可能希望让转换函数在m
中失败,要求它的类型为(a -> m b)
。
我已经在镜头库中查找了这种功能,但是找不到,所以我实现了:
modifyingM l f = use l >>= f >>= assign l
哪个可以解决问题,但我想知道镜头库中是否已经有一个函数可以做到这一点。
答案 0 :(得分:6)
我什么都没看到。 ASetter
已定义
type ASetter s t a b = (a -> Identity b) -> s -> Identity t
因此它的功能还不够强大(Setter
也无法做到)。另一方面,事实证明Lens
比必需的要强一些。那么,让我们考虑如何使用Traversal
。
type Traversal s t a b =
forall f. Applicative f => (a -> f b) -> s -> f t
所以
Traversal s s a b =
forall f. Applicative f => (a -> f b) -> s -> f s
我们想要哪个Applicative
? m
似乎是一个显而易见的尝试。当我们通过遍历a -> m b
时,我们将返回s -> m s
。大!与lens
一样,我们实际上只要求用户提供一个ATraversal
,我们可以对其进行克隆。
modifyingM
:: MonadState s m
=> ATraversal s s a b
-> (a -> m b) -> m ()
modifyingM t f = do
s <- get
s' <- cloneTraversal t f s
put s'
这很好,因为它只遍历一次状态。
即使那是矫kill过正。实际上,最自然的事情是
modifyingM
:: MonadState s m
=> LensLike m s s a b
-> (a -> m b) -> m ()
modifyingM t f = do
s <- get
s' <- t f s
put s'
您可以将其直接应用于Traversal
,Lens
,Iso
或Equality
,或使用cloneTraversal
,cloneLens
,{ {1}},或者(希望在cloneIso
的下一版本中)lens
将其应用于单态变体。