Boost.Hana  1.6.0
Your standard library for metaprogramming
Applicative

Description

The Applicative concept represents Functors with the ability to lift values and combine computations.

A Functor can only take a normal function and map it over a structure containing values to obtain a new structure containing values. Intuitively, an Applicative can also take a value and lift it into the structure. In addition, an Applicative can take a structure containing functions and apply it to a structure containing values to obtain a new structure containing values. By currying the function(s) inside the structure, it is then also possible to apply n-ary functions to n structures containing values.

Note
This documentation does not go into much details about the nature of applicatives. However, the Typeclassopedia is a nice Haskell-oriented resource where such information can be found.

Minimal complete definition

lift and ap satisfying the laws below. An Applicative must also be a Functor.

Laws

Given an Applicative F, the following laws must be satisfied:

  1. Identity
    For all objects xs of tag F(A),
    ap(lift<F>(id), xs) == xs
  2. Composition
    For all objects xs of tag F(A) and functions-in-an-applicative \( fs : F(B \to C) \), \( gs : F(A \to B) \),
    ap(ap(lift<F>(compose), fs, gs), xs) == ap(fs, ap(gs, xs))
  3. Homomorphism
    For all objects x of tag A and functions \( f : A \to B \),
    ap(lift<F>(f), lift<F>(x)) == lift<F>(f(x))
  4. Interchange
    For all objects x of tag A and functions-in-an-applicative \( fs : F(A \to B) \),
    ap(fs, lift<F>(x)) == ap(lift<F>(apply(-, x)), fs)
    where apply(-, x) denotes the partial application of the apply function from the Functional module to the x argument.

As a consequence of these laws, the model of Functor for F will satisfy the following for all objects xs of tag F(A) and functions \( f : A \to B \):

transform(xs, f) == ap(lift<F>(f), xs)

Refined concept

  1. Functor (free model)
    As a consequence of the laws, any Applicative F can be made a Functor by setting
    transform(xs, f) = ap(lift<F>(f), xs)

Concrete models

hana::lazy, hana::optional, hana::tuple

Structure-preserving functions

An applicative transformation is a function \( t : F(X) \to G(X) \) between two Applicatives F and G, where X can be any tag, and which preserves the operations of an Applicative. In other words, for all objects x of tag X, functions-in-an-applicative \( fs : F(X \to Y) \) and objects xs of tag F(X),

t(lift<F>(x)) == lift<G>(x)
t(ap(fs, xs)) == ap(t(fs), t(xs))

Variables

constexpr auto boost::hana::ap
 Lifted application.Specifically, ap applies a structure containing functions to a structure containing values, and returns a new structure containing values. The exact way in which the functions are applied to the values depends on the Applicative. More...
 
template<typename A >
constexpr auto boost::hana::lift
 Lift a value into an Applicative structure.lift<A> takes a normal value and embeds it into a structure whose shape is represented by the A Applicative. Note that the value may be a function, in which case the created structure may be applied to another Applicative structure containing values. More...
 

Variable Documentation

◆ ap

constexpr auto boost::hana::ap

#include <boost/hana/fwd/ap.hpp>

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

Lifted application.Specifically, ap applies a structure containing functions to a structure containing values, and returns a new structure containing values. The exact way in which the functions are applied to the values depends on the Applicative.

ap can be called with two arguments or more; the functions in the f structure are curried and then applied to the values in each x... structure using the binary form of ap. Note that this requires the number of x... must match the arity of the functions in the f structure. In other words, ap(f, x1, ..., xN) is equivalent to

((curry(f) ap x1) ap x2) ... ap xN

where x ap y is just ap(x, y) written in infix notation to emphasize the left associativity.

Signature

Given an Applicative A, the signature is \( \mathtt{ap} : A(T_1 \times \cdots \times T_n \to U) \times A(T_1) \times \cdots \times A(T_n) \to A(U) \).

Parameters
fA structure containing function(s).
x...Structure(s) containing value(s) and on which f is applied. The number of structures must match the arity of the functions in the f structure.

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>
namespace hana = boost::hana;
int main() {
// with tuples
static_assert(
hana::ap(hana::make_tuple(std::plus<>{}), hana::make_tuple(1, 2),
hana::make_tuple(3, 4, 5))
==
hana::make_tuple(
1 + 3, 1 + 4, 1 + 5,
2 + 3, 2 + 4, 2 + 5
)
, "");
// with optional values
BOOST_HANA_CONSTEXPR_LAMBDA auto multiply = [](auto a, auto b, auto c) {
return a * b * c;
};
hana::ap(hana::just(multiply), hana::just(1),
hana::just(2),
hana::just(3))
==
hana::just(1 * 2 * 3)
);
hana::ap(hana::just(multiply), hana::just(1),
hana::nothing,
hana::just(3))
==
hana::nothing
);
}
Todo:
Consider giving access to all the arguments to the tag-dispatched implementation for performance purposes.

◆ lift

template<typename A >
constexpr auto boost::hana::lift

#include <boost/hana/fwd/lift.hpp>

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

Lift a value into an Applicative structure.lift<A> takes a normal value and embeds it into a structure whose shape is represented by the A Applicative. Note that the value may be a function, in which case the created structure may be applied to another Applicative structure containing values.

Signature

Given an Applicative A, the signature is \( \mathtt{lift}_A : T \to A(T) \).

Template Parameters
AA tag representing the Applicative into which the value is lifted.
Parameters
xThe value to lift into the applicative.

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::lift<hana::tuple_tag>('x') == hana::make_tuple('x'), "");
static_assert(hana::lift<hana::optional_tag>('x') == hana::just('x'), "");
int main() { }