Я часто читал, чтоПочему Идентификационная монада полезна?
Кажется, что идентичная монада бесполезна. Это не ... но это еще одна тема .
Так может кто-нибудь сказать мне, как это полезно?
Я часто читал, чтоПочему Идентификационная монада полезна?
Кажется, что идентичная монада бесполезна. Это не ... но это еще одна тема .
Так может кто-нибудь сказать мне, как это полезно?
Identity
является монады, функторов и аппликативных функторы 0 номерамов. Само по себе это кажется бесполезным, но часто это необходимо в местах, где можно ожидать, что монада или (аппликативный) функтор фактически ничего не делают.
Как уже упоминалось, Identity
позволяет нам определять только монадные трансформаторы, а затем определять их соответствующие монады как SomeT Identity
.
Но это еще не все. Часто бывает удобно также определять другие понятия в терминах монадов, что обычно добавляет большую гибкость. Например, Conduit i m o
(также см. this tutorial) определяет элемент в конвейере, который может запрашивать данные типа i
, может создавать данные типа o
и использует монаду m
для внутренней обработки. Затем такой трубопровод может работать в данной монаде с использованием
($$) :: Monad m => Source m a -> Sink a m b -> m b
(где Source
является псевдонимом для Conduit
, без ввода и Sink
для Conduit
без выхода). А когда нет effectful вычисления не нужно в трубопроводе, только чистый код, мы просто специализируемся m
на Identity
и запустить такой трубопровод, как
runIdentity (source $$ sink)
Identity
также «пустой» функтор и аппликативен функтор: Identity
состоящий из другого функтора или аппликативного функтора, изоморфен оригиналу. Например, Lens'
определяется как функция полиморфной в Functor
:
Functor f => (a -> f a) -> s -> f s
грубо говоря, такая линза позволяет считывать или манипулировать что-то типа a
внутри s
, например, поле внутри записи (для введения к объективам см. this post). Если мы специализируемся f
на Identity
, мы получаем
(a -> Identity a) -> s -> Identity s
изоморфная
(a -> a) -> s -> s
так дано функция обновления на a
, возвращает функцию обновления на s
. (Для полноты: Если мы специализируемся f
на Const a
, мы получаем (a -> Const b a) -> s -> Const b s
, которая изоморфна (a -> b) -> (s -> b)
, то есть, учитывая читателя на a
, возвращают читателя на s
.)
Один реальный случай использования должен быть (чистым) основанием стека трансформаторов монады, например.
type Reader r = ReaderT r Identity
Одно использование его в качестве базы для монады монад трансформаторных стеков: вместо того, чтобы обеспечить два типа Some :: * ->*
и SomeT :: (* -> *) -> * -> *
, достаточно, чтобы обеспечить только путем установки последней type Some = SomeT Identity
.
Другие, несколько напоминает случай использования (но полностью оторван от всей монады бизнеса), когда вам нужно сослаться на кортежи: мы можем сказать, ()
является нульарной кортеж, (a, b)
двоичным кортеж, (a, b, c)
является тройной кортеж, и так далее, но что это оставляет для унарного дела? Высказывание a
является унарным кортежем для любого выбора a
часто не является удовлетворительным, например, когда мы создаем некоторые экземпляры типа typeclass, такие как Data.Tuple.Select
, для создания однозначного ключа необходим некоторый конструктор типов. Таким образом, путем добавления, например, Sel1
экземпляров до Identity a
, это заставляет нас различать (a, b)
(двухкортеж, содержащий a
и b
) и Identity (a, b)
(один кортеж, содержащий одно значение (a, b)
).
(Обратите внимание, что Data.Tuple.Select
определяет свой собственный тип, называемый OneTuple
вместо использования Identity
, но она изоморфна Identity
-в самом деле, это просто переименовать прочь и я думаю, что существует только, чтобы избежать не- base
зависимости.)
«Идентичность» все равно соединяется с базой в 4.8, так что скоро может стать историческим артефактом. «Data.Sequence» использует внутренний тип «Elem» (также изоморфный «Identity»). – dfeuer
Иногда я работаю с записями, поля которых являются необязательными в некоторых контекстах (например, при анализе записи из JSON), но обязательно в других.
Я решаю это путем параметризации записи с помощью функтора и используя Maybe
или Identity
в каждом случае.
{-# LANGUAGE DeriveGeneriC#-}
{-# LANGUAGE StandaloneDeriving #-}
data Query f = Query
{
_viewName :: String
, _target :: f Server -- Server is some type, it doesn't matter which
}
deriving (Generic)
поле сервер не является обязательным при обработке JSON:
instance FromJSON (Query Maybe)
Но тогда у меня есть функция, как
withDefaultServer :: Server -> Query Maybe -> Query Identity
withDefaultServer = undefined
, который возвращает записи, в которой _target
поле является обязательным.
(Этот ответ ничего одноместный о Identity
не использует, хотя.)
Я вижу это как отличный инструмент для объяснения монады для людей, не имеющих прежних знаний об этом виде вещей, и как ценное упражнение для любого, кто научится применять монады. – ThreeFx