Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Identity monad useful?

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?

like image 511
piotrek Avatar asked Feb 21 '15 11:02

piotrek


People also ask

What is the purpose of a monad?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What is the difference between functor and monad?

A functor takes a pure function (and a functorial value) whereas a monad takes a Kleisli arrow, i.e. a function that returns a monad (and a monadic value). Hence you can chain two monads and the second monad can depend on the result of the previous one.

What is monad in programming?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.

Could you comfortably explain the difference between a monad and an applicative functor?

Functors apply a function to a wrapped value: Applicatives apply a wrapped function to a wrapped value: Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function >>= (pronounced "bind") to do this.


2 Answers

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.)

like image 126
Petr Avatar answered Oct 04 '22 23:10

Petr


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.)

like image 37
danidiaz Avatar answered Oct 04 '22 23:10

danidiaz