16

I often read that

It seem that identity monad is useless. It's not... but that's another topic.

So can anyone tell my how is it useful?

1
  • 1
    I see it as a great tool to explain monads to people with no former knowledge on this kind of stuff and as a valuable exercise for anybody learning how to implement monads.
    – ThreeFx
    Commented Feb 21, 2015 at 12:07

4 Answers 4

26

Identity is to monads, functors and applicative functors as 0 is to numbers. On its own it seems useless, but it's often needed in places where one expects a monad or an (applicative) functor that actually doesn't do anything.

As already mentioned, Identity allows us to define just monad transformers and then define their corresponding monads just as SomeT Identity.

But that's not all. It's often convenient to also define other concepts in terms of monads, which usually adds a lot of flexibility. For example Conduit i m o (also see this tutorial) defines an element in a pipeline that can request data of type i, can produce data of type o, and uses monad m for internal processing. Then such a pipeline can be run in the given monad using

($$) :: Monad m => Source m a -> Sink a m b -> m b

(where Source is an alias for Conduit with no input and Sink for Conduit with no output). And when no effectful computations are needed in the pipeline, just pure code, we just specialize m to Identity and run such a pipeline as

runIdentity (source $$ sink)

Identity is also the "empty" functor and applicative functor: Identity composed with another functor or applicative functor is isomorphic to the original. For example, Lens' is defined as a function polymorphic in a Functor:

Functor f => (a -> f a) -> s -> f s

roughly speaking, such a lens allows to read or manipulate something of type a inside s, for example a field inside a record (for an introduction to lenses see this post). If we specialize f to Identity, we get

(a -> Identity a) -> s -> Identity s

which is isomorphic to

(a -> a) -> s -> s

so given an updating function on a, return an updating function on s. (For completeness: If we specialize f to Const a, we get (a -> Const b a) -> s -> Const b s, which is isomorphic to (a -> b) -> (s -> b), that is, given a reader on a, return a reader on s.)

11

Sometimes I work with records whose fields are optional in some contexts (like when parsing the record from JSON) but mandatory in others.

I solve that by parametrizing the record with a functor, and using Maybe or Identity in each case.

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}

data Query f = Query
    {
        _viewName :: String
    ,   _target :: f Server -- Server is some type, it doesn't matter which
    }
    deriving (Generic)

The server field is optional when parsing JSON:

instance FromJSON (Query Maybe)

But then I have a function like

withDefaultServer :: Server -> Query Maybe -> Query Identity 
withDefaultServer = undefined

that returns a record in which the _target field is mandatory.

(This answer doesn't use anything monadic about Identity, though.)

10

One use of it is as a base monad for monad transformer stacks: instead of having to provide two types Some :: * ->* and SomeT :: (* -> *) -> * -> *, it is enough to provide just a latter by setting type Some = SomeT Identity.

Another, somewhat similar use case (but completely detached from the whole monad business) is when you need to refer to tuples: we can say () is a nullary tuple, (a, b) is a binary tuple, (a, b, c) is a ternary tuple, and so on, but what does that leave for the unary case? Saying a is a unary tuple for any choice of a is often not satisfactory, for example when we are building some typeclass instances like Data.Tuple.Select, some type constructor is needed to act as the unambiguous key. So by adding e.g. Sel1 instances to Identity a, it forces us to distinguish between (a, b) (a two-tuple containing an a and a b), and Identity (a, b) (a one-tuple containing a single (a, b) value).

(Note that Data.Tuple.Select defines its own type called OneTuple instead of reusing Identity, but it is isomorphic to Identity—in fact, it's just a rename away—and I think it only exists to avoid a non-base dependency.)

1
  • 1
    Identity is joining base in 4.8 anyway, so that may soon be a historical artifact. Data.Sequence uses an internal Elem type (also isomorphic to Identity) in these ways.
    – dfeuer
    Commented Feb 21, 2015 at 14:13
4

One real use-case is to be a (pure) base of monad transformers stack, e.g.

type Reader r = ReaderT r Identity

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.