Boost.Hana  1.3.0
Your standard library for metaprogramming
Comonad

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:

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
wThe value to wrap in an additional level of comonadic context.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
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
wA comonadic value to call the function with.
fA function of signature \( W(T) \to U \) to be applied to its comonadic argument inside the comonadic context.

Example

// Copyright Louis Dionne 2013-2017
// 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 <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;
});
}
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
wThe value to be extracted inside a comonadic context.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
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() { }