Boost.Hana: Comonad

| Boost.Hana 1.0.0 Your standard library for metaprogramming |

Variables
Comonad
Concepts

## Description

The `Comonad` concept represents context-sensitive computations and data.

Formally, the Comonad concept is dual to the Monad concept. But unless you're a mathematician, you don't care about that and it's fine. So intuitively, a Comonad represents context sensitive values and computations. First, Comonads make it possible to extract context-sensitive values from their context with `extract`. In contrast, Monads make it possible to wrap raw values into a given context with `lift` (from Applicative).

Secondly, Comonads make it possible to apply context-sensitive values to functions accepting those, and to return the result as a context-sensitive value using `extend`. In contrast, Monads make it possible to apply a monadic value to a function accepting a normal value and returning a monadic value, and to return the result as a monadic value (with `chain`).

Finally, Comonads make it possible to wrap a context-sensitive value into an extra layer of context using `duplicate`, while Monads make it possible to take a value with an extra layer of context and to strip it with `flatten`.

Whereas `lift`, `chain` and `flatten` from Applicative and Monad have signatures

\begin{align*} \mathtt{lift}_M &: T \to M(T) \\ \mathtt{chain} &: M(T) \times (T \to M(U)) \to M(U) \\ \mathtt{flatten} &: M(M(T)) \to M(T) \end{align*}

`extract`, `extend` and `duplicate` from Comonad have signatures

\begin{align*} \mathtt{extract} &: W(T) \to T \\ \mathtt{extend} &: W(T) \times (W(T) \to U) \to W(U) \\ \mathtt{duplicate} &: W(T) \to W(W(T)) \end{align*}

Notice how the "arrows" are reversed. This symmetry is essentially what we mean by Comonad being the dual of Monad.

Note
  The Typeclassopedia is a nice Haskell-oriented resource for further reading about Comonads.

## Minimal complete definition

`extract` and (`extend` or `duplicate`) satisfying the laws below. A `Comonad` must also be a `Functor`.

## Laws

For all Comonads `w`, the following laws must be satisfied:

extract(duplicate(w)) == w
transform(duplicate(w), extract) == w
duplicate(duplicate(w)) == transform(duplicate(w), duplicate)

Note
  There are several equivalent ways of defining Comonads, and this one is just one that was picked arbitrarily for simplicity.

## Refined concept

1. Functor
   Every Comonad is also required to be a Functor. At first, one might think that it should instead be some imaginary concept CoFunctor. However, it turns out that a CoFunctor is the same as a `Functor`, hence the requirement that a `Comonad` also is a `Functor`.

## Concrete models

`hana::lazy`

## Variables

constexpr auto | boost::hana::duplicate

Add an extra layer of comonadic context to a comonadic value.Given a value already in a comonadic context, `duplicate` wraps this value with an additional layer of comonadic context. This can be seen as the dual operation to `flatten` from the Monad concept. More...

constexpr auto | boost::hana::extend
| Comonadic application of a function to a comonadic value.Given a comonadic value and a function accepting a comonadic input, `extend` returns the result of applying the function to that input inside the comonadic context. More...
constexpr auto | boost::hana::extract

Extract a value in a given comonadic context.Given a value inside a comonadic context, extract it from that context, performing whatever effects are mandated by that context. This can be seen as the dual operation to the `lift` method of the Applicative concept. More...

## Variable Documentation

constexpr auto boost::hana::duplicate

`#include <boost/hana/fwd/duplicate.hpp>`

Initial value:
= [](auto&& w) -> decltype(auto) {
return tag-dispatched;
}

Add an extra layer of comonadic context to a comonadic value.Given a value already in a comonadic context, `duplicate` wraps this value with an additional layer of comonadic context. This can be seen as the dual operation to `flatten` from the Monad concept.

## Signature

Given a Comonad `W`, the signature is \( \mathtt{duplicate} : W(T) \to W(W(T)) \)

Parameters

  w | The value to wrap in an additional level of comonadic context.

## Example

// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <boost/hana/duplicate.hpp>
#include <boost/hana/extract.hpp>
#include <boost/hana/lazy.hpp>
namespace hana = boost::hana;
int main() {
constexpr auto very_lazy = hana::duplicate(hana::make_lazy(3));
static_assert(hana::extract(hana::extract(very_lazy)) == 3, "");
}

constexpr auto boost::hana::extend

`#include <boost/hana/fwd/extend.hpp>`

Initial value:
= [](auto&& w, auto&& f) -> decltype(auto) {
return tag-dispatched;
}

Comonadic application of a function to a comonadic value.Given a comonadic value and a function accepting a comonadic input, `extend` returns the result of applying the function to that input inside the comonadic context.

## Signature

Given a Comonad `W` and a function of type \( W(T) \to U \), the signature is \( \mathtt{extend} : W(T) \times (W(T) \to U) \to W(U) \)

Parameters

  w | A comonadic value to call the function with.
  f | A function of signature \( W(T) \to U \) to be applied to its comonadic argument inside the comonadic context.

## Example

// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <boost/hana/assert.hpp>
#include <boost/hana/eval.hpp>
#include <boost/hana/extend.hpp>
#include <boost/hana/extract.hpp>
#include <boost/hana/lazy.hpp>
#include <functional>
#include <istream>
#include <sstream>
namespace hana = boost::hana;
template <typename T>
T read_one(std::istream& s) {
T value;
s >> value;
return value;
}
int main() {
std::stringstream s;
s << "1 2 3";
auto from_stream = hana::extend(hana::make_lazy(read_one<int>)(std::ref(s)), [](auto i) {
return hana::eval(i) + 1;
});
BOOST_HANA_RUNTIME_CHECK(hana::extract(from_stream) == 2);
BOOST_HANA_RUNTIME_CHECK(hana::extract(from_stream) == 3);
BOOST_HANA_RUNTIME_CHECK(hana::extract(from_stream) == 4);
}

constexpr auto boost::hana::extract

`#include <boost/hana/fwd/extract.hpp>`

Initial value:
= [](auto&& w) -> decltype(auto) {
return tag-dispatched;
}

Extract a value in a given comonadic context.Given a value inside a comonadic context, extract it from that context, performing whatever effects are mandated by that context. This can be seen as the dual operation to the `lift` method of the Applicative concept.

## Signature

Given a Comonad `W`, the signature is \( \mathtt{extract} : W(T) \to T \)

Parameters

  w | The value to be extracted inside a comonadic context.

## Example

// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <boost/hana/extract.hpp>
#include <boost/hana/functional/placeholder.hpp>
#include <boost/hana/lazy.hpp>
namespace hana = boost::hana;
static_assert(hana::extract(hana::make_lazy(1)) == 1, "");
static_assert(hana::extract(hana::make_lazy(hana::_ + 1)(3)) == 4, "");
int main() { }