Модификация объектива с ошибкой - PullRequest
4 голосов
/ 06 июля 2019

В 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

Что и делает, но мне было интересно, есть ли уже функция в библиотеке объективов, которая сделает это.

1 Ответ

6 голосов
/ 06 июля 2019

Я не вижу ничего подобного.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, мы надеемся) cloneEquality, чтобы применить его к мономорфным вариантам.

...