haskell - 镜头修改失败

标签 haskell haskell-lens

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

哪个有窍门,但我想知道镜头库中是否已经有一个功能可以做到这一点。

最佳答案

我没有看到类似的东西。 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'

这很好,因为它只遍历状态一次。

即使这样也太过分了,真的。最自然的其实是
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 , cloneIso ,或(在 lens-4.18 或更高版本中)cloneEquality将其应用于单态变体。

关于haskell - 镜头修改失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56909497/

相关文章:

haskell - 镜片和 zipper 有什么区别?

haskell - 将 Lens 组合成元组的 Lens

haskell - 如何将临时多态类型声明为特定类型类的实例?

Haskell 导入 MissingH

haskell - 是否可以为我奇怪的类似枚举类型声明 FromJSON 实例?

c# - 关于 Haskell -> C# 转换的问题

haskell - 如何在镜头中使用过载的记录场?

json - 如何使用 Haskell Lens 重写 JSON 结构中的任意嵌套字段?

haskell - 融合遍历

haskell - 使用存在类型 Haskell 时出现类型错误