Что такое магазин в скалазе
Я пытаюсь понять Lens
эс в scalaz
(на удивление не нашел ничего похожего в cats-core
) и мне попалось так называемое Store
который является псевдонимом типа:
type StoreT[F[_], A, B] = IndexedStoreT[F, A, A, B]
type IndexedStore[I, A, B] = IndexedStoreT[Id, I, A, B]
type Store[A, B] = StoreT[Id, A, B]
куда
final case class IndexedStoreT[F[_], +I, A, B](run: (F[A => B], I))
Вопрос в том, как лечить этот тип? Документация просто ссылается на Lens
эс. Может кто-нибудь дать объяснение в нескольких словах?
Для меня это похоже на State
монада, где "переход состояния" хранится с функцией F[A => B]
1 ответ
Store[S,A]
это структура, полная A
s, проиндексированный S
с выдающимся S
как своего рода "курсор" в структуру.
Чтобы ответить на вопрос "что это?", Наиболее поучительно посмотреть, какие операции он поддерживает.
Вы можете запросить положение курсора:
_.pos : Store[S,A] => S
Вы можете "посмотреть" на значение под курсором:
_.peek : Store[S,A] => A
И вы можете "искать" для перемещения курсора:
_ seek _ : (Store[S,A], S) => Store[S,A]
Думайте об этом как массив измерений S
где у вас есть индекс s:S
в массив, и вы можете переместить индекс.
Например, Store[(Int,Int), Byte]
является двумерным 256-цветным растровым изображением. Вы можете peek
в цвете (представленном байтом) пикселя под курсором, и вы можете переместить курсор в другой пиксель, используя seek
,
Магазин Comonad
Store[S,_]
тоже комонад. Это означает, что он поддерживает следующие операции:
map : (A => B) => (Store[S,A] => Store[S,B])
extend : (Store[S,A] => B) => (Store[S,A] => Store[S,B])
duplicate : Store[S,A] => Store[S, Store[S, A]]
map
означает, что вы можете изменить все значения в магазине, используя функцию.
s.extend(f)
занимает "локальное" вычисление f
, который работает в магазине в определенном месте S
и распространяет его на "глобальные" вычисления, которые работают с хранилищем в любом месте. В примере растрового изображения, если у вас есть функция mean(store)
который принимает среднее значение пикселей, непосредственно окружающих курсор в store
, затем store.extend(mean)
выполнит фильтр Гаусса для всего изображения. Каждый пиксель в новом изображении будет представлять собой среднее значение пикселей, непосредственно окружающих пиксели в этом месте исходного изображения.
s.duplicate
дает вам Store[S,Store[S,A]]
полон Store[S,A]
с, что в каждом месте S
имеет копию оригинала Store[S,A]
с его курсором в этом месте S
,
Отношение к государству
Store
двойственный State
, Под капотом, State[S,A]
действительно S => (A, S)
, а также Store[S,A]
действительно (S => A, S)
:
State[S,A] ~= S => (A, S)
Store[S,A] ~= (S => A, S)
Оба состоят из двух функторов S => _
а также (_, S)
, Если вы составите их одним способом, вы получите State[S,_]
, Если вы составите их по-другому, вы получите Store[S,_]
,
Я говорил об этом пару раз:
https://www.youtube.com/watch?v=FuOZjYVb7g0
Классный способ использования этой двойственности заключается в том, что если у вас есть магазин и конечный автомат, они уничтожают друг друга. Хранилище управляет конечным автоматом, и, в свою очередь, конечный автомат выбирает значение из хранилища.
def zap[S,A,B](state: State[S,A], store: Store[S,B]): (A,B) = {
val (a, s) = state.run(store.pos)
(a, store.seek(s).peek)
}