Ho letto spesso chePerché è utile Monnal Identity?
Sembra che la monade dell'identità sia inutile. Non è ... ma questo è un altro argomento .
Così qualcuno può dire come è utile?
Ho letto spesso chePerché è utile Monnal Identity?
Sembra che la monade dell'identità sia inutile. Non è ... ma questo è un altro argomento .
Così qualcuno può dire come è utile?
Identity
è quello di monadi, funtori e funtori applicative come 0 è di numeri. Di per sé sembra inutile, ma è spesso necessario nei luoghi in cui ci si aspetta una monade o un funtore (applicativo) che in realtà non fa nulla.
Come già menzionato, Identity
permette di definire trasformatori solo monad e quindi definire le monadi corrispondenti altrettanto SomeT Identity
.
Ma non è tutto. Spesso è anche utile definire altri concetti in termini di monadi, che di solito aggiungono molta flessibilità. Ad esempio Conduit i m o
(vedi anche this tutorial) definisce un elemento in una pipeline che può richiedere dati di tipo i
, può produrre dati di tipo o
e utilizza la tecnologia monad m
per l'elaborazione interna. Allora tale tubazione può essere eseguito in monade determinato utilizzando
($$) :: Monad m => Source m a -> Sink a m b -> m b
(dove Source
è un alias per Conduit
senza ingresso e Sink
per Conduit
senza output). E quando non sono necessari calcoli effectful in cantiere, il codice solo pura, abbiamo appena specializziamo m
-Identity
ed eseguire tale gasdotto come
runIdentity (source $$ sink)
Identity
è anche il funtore "vuoto" e funtore applicativa: Identity
composto con un altro funtore o funtore applicativo isomorfo all'originale. Ad esempio, Lens'
è definito come un polimorfica funzione in un Functor
:
Functor f => (a -> f a) -> s -> f s
grosso modo, una tale lente permette di leggere o manipolare qualcosa di tipo a
all'interno s
, ad esempio un campo all'interno di un disco (per un'introduzione agli obiettivi vedere this post). Se specializzati f
-Identity
, otteniamo
(a -> Identity a) -> s -> Identity s
che è isomorfo a
(a -> a) -> s -> s
così data una funzione di aggiornamento sulla a
, restituire una funzione di aggiornamento sui s
. (Per completezza: Se specializzati f
-Const a
, otteniamo (a -> Const b a) -> s -> Const b s
, che è isomorfo a (a -> b) -> (s -> b)
, cioè, dato un lettore su a
, restituiscono un lettore su s
.)
Un caso d'uso reale deve essere una base (pura) di stack di trasformatori monad, ad es.
type Reader r = ReaderT r Identity
Un uso di esso è come monade base per monad pile trasformatori: invece di dover prevedere due tipi Some :: * ->*
e SomeT :: (* -> *) -> * -> *
, è sufficiente fornire solo un secondo di impostazione type Some = SomeT Identity
.
Un altro, un po 'simile caso d'uso (ma completamente staccato da tutta la faccenda Monade) è quando è necessario fare riferimento alle tuple: possiamo dire ()
è una tupla nullaria, (a, b)
è una tupla binario, (a, b, c)
è una tupla ternario, e così via, ma cosa lascia per caso unario? Dire a
è una tupla unaria per qualsiasi scelta di a
che spesso non è soddisfacente, ad esempio quando stiamo costruendo alcune istanze di typeclass come Data.Tuple.Select
, qualche tipo di costruttore è necessario per fungere da chiave non ambigua. Quindi aggiungendo per es. Sel1
istanze a Identity a
, ci costringe a distinguere tra (a, b)
(una doppia tupla contenente uno a
e uno b
) e Identity (a, b)
(una tupla singola contenente un singolo valore (a, b)
).
(Si noti che Data.Tuple.Select
definisce il suo proprio tipo chiamato OneTuple
invece di riutilizzare Identity
, ma è isomorfo a Identity
fatto -in, è solo un rinomina lontano e ritengo esiste solo per evitare una non base
dipendenza.)
'Identity' si sta unendo alla base in 4.8 comunque, in modo che possa presto essere un artefatto storico. 'Data.Sequence' usa un tipo' Elem' interno (anche isomorfo a 'Identity') in questi modi. – dfeuer
A volte lavoro con i record i cui campi sono facoltativi in alcuni contesti (come quando si analizza il record da JSON) ma obbligatorio in altri.
Io lo risolvo parametrizzando il record con un funtore e usando Maybe
o Identity
in ciascun caso.
{-# LANGUAGE DeriveGeneriC#-}
{-# LANGUAGE StandaloneDeriving #-}
data Query f = Query
{
_viewName :: String
, _target :: f Server -- Server is some type, it doesn't matter which
}
deriving (Generic)
campo Server è facoltativo durante l'analisi JSON:
instance FromJSON (Query Maybe)
Ma poi ho una funzione come
withDefaultServer :: Server -> Query Maybe -> Query Identity
withDefaultServer = undefined
che restituisce un record in cui il campo _target
è obbligatorio.
(Questa risposta non usa nulla monadica su Identity
, però.)
lo vedo come un grande strumento per spiegare monadi a persone senza precedenti conoscenze su questo genere di cose e come un esercizio prezioso per chiunque impari come implementare le monadi. – ThreeFx